<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://sneslab.net/mw/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Anonimzwx</id>
	<title>SnesLab - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://sneslab.net/mw/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Anonimzwx"/>
	<link rel="alternate" type="text/html" href="https://sneslab.net/wiki/Special:Contributions/Anonimzwx"/>
	<updated>2026-10-29T02:52:45Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.11</generator>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=Dynamic_Xtreme&amp;diff=21403</id>
		<title>Dynamic Xtreme</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=Dynamic_Xtreme&amp;diff=21403"/>
		<updated>2026-10-25T22:16:39Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme is a tool for dynamic graphics and palettes in Super Mario World on the SNES, created by [[User:Anonimzwx|Anonimzwx]] as the successor to Dynamic Z and Dynamic X. Built for the ROM hacking community, it lets graphics and colors change in real time during gameplay. Its dynamic graphics system is flexible and modular, with a focus on performance.&lt;br /&gt;
&lt;br /&gt;
A dynamic sprite loads resources, such as graphics or palettes, in real time during gameplay. A static sprite uses resources that were already loaded when the level began.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme does not break the SNES hardware limits: it works within them, optimizing memory use and transfers to reduce their impact and make them much less noticeable during gameplay.&lt;br /&gt;
&lt;br /&gt;
Its main features include:&lt;br /&gt;
* Real-time (on-the-fly) graphics and palette changes.&lt;br /&gt;
* The most powerful and flexible dynamic sprite system available for Super Mario World.&lt;br /&gt;
* An Advanced Drawing System that can draw any registered frame on screen, with full control over priority, layer, offsets, and properties.&lt;br /&gt;
* Advanced palette effects, including real-time changes to hue, saturation, brightness, color blending, smooth transitions, and individual RGB and HSL channels.&lt;br /&gt;
* Complete replacement of player graphics and palettes, supporting any Mario size, any number of frames, and any animation style.&lt;br /&gt;
* Yoshi graphics replacement using a layout like the original game&#039;s.&lt;br /&gt;
* Extensive NMI handler optimizations to maximize performance.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme&#039;s features are selected during installation so a project can use only what it needs. Some have dependencies, compatibility issues, or restrictions on uninstalling them; check each option&#039;s warnings. The tool aims to make complex visual effects easier to implement in Super Mario World hacks while maintaining a high level of compatibility and stability.&lt;br /&gt;
&lt;br /&gt;
== Project goals ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme&#039;s main goal is to make dynamic sprites easier to use and provide full support for real-time graphics, palette, and tilemap changes.&lt;br /&gt;
&lt;br /&gt;
The project aims to make the most of the SNES without requiring advanced knowledge of the console&#039;s internal hardware. Traditional dynamic systems are often complex and rely heavily on technical concepts such as VRAM, CGRAM, OAM, and DMA. Dynamic Xtreme hides much of that complexity behind more modern, readable tools and formats that are easier to use.&lt;br /&gt;
&lt;br /&gt;
Another main goal is to maintain high performance even in visually complex situations, allowing extensive use of dynamic graphics, palette effects, and advanced drawing systems without unnecessarily compromising performance.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme also aims to make dynamic sprites as natural and straightforward to use as regular sprites. People focused on level design or content creation should be able to work with dynamic resources without constantly worrying about the system&#039;s internal technical limitations.&lt;br /&gt;
&lt;br /&gt;
== Features ==&lt;br /&gt;
&lt;br /&gt;
During installation, you can choose which features to enable. The names in parentheses match the installer options and &amp;lt;code&amp;gt;Settings.json&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Graphics, poses, and palettes ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Graphics changes (&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;) || Allows graphics to be loaded during gameplay. This is the foundation for tile animations, level graphics changes, and dynamic poses.&lt;br /&gt;
|-&lt;br /&gt;
| Palette changes (&amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;) || Allows palettes to be loaded and managed during gameplay. Includes automatic palette assignment so sprites can share the same colors without loading them multiple times.&lt;br /&gt;
|-&lt;br /&gt;
| Dynamic poses (&amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;) || Manages VRAM space as a pose cache: reuses loaded poses, shares them between entities, and chooses which ones to replace when more space is needed. This avoids unnecessary loads.&lt;br /&gt;
|-&lt;br /&gt;
| Pose drawing (&amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;) || Draws both dynamic and static poses defined in DrawInfo files. Allows control over their tiles, position, flipping, palette, and drawing priority.&lt;br /&gt;
|-&lt;br /&gt;
| Palette effects (&amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;) || Changes colors using RGB and HSL effects: tinting palettes, adjusting hue, saturation, or lightness, and making transitions between palettes. Effects can apply to individual resources or globally.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Dynamic pose loading and drawing are separate systems: you can draw a static pose without loading its graphics dynamically.&lt;br /&gt;
&lt;br /&gt;
=== Player and Yoshi ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Player features (&amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;) || Allows player graphics and palettes to be changed and adapts player drawing and pose loading for custom systems. Also allows the player to be hidden or dynamic uploads to be disabled. May conflict with patches that modify player graphics or palettes; read the installer warning before enabling it.&lt;br /&gt;
|-&lt;br /&gt;
| Yoshi features (&amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;) || Allows Yoshi&#039;s graphics to be changed while retaining the original pose layout. Requires &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; and shares its compatibility restrictions.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory and optimizations ===&lt;br /&gt;
&lt;br /&gt;
These options reorganize some of the game&#039;s work to leave more time for graphics and palette transfers. NMI is the routine that updates the display during the interval between frames.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Free the &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt; area (&amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;) || On ROMs without SA-1, avoids keeping certain original player, Yoshi, and animation graphics in RAM and reads them from ROM instead. Dynamic Xtreme uses the recovered space for its internal variables; it is not freely available for other uses without reservation. This option does not apply to SA-1 ROMs.&lt;br /&gt;
|-&lt;br /&gt;
| Controller optimization (&amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;) || Moves controller processing out of NMI to leave more time for display updates.&lt;br /&gt;
|-&lt;br /&gt;
| Fixed color optimization (&amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;) || Reduces NMI work for updating the fixed color used by the game&#039;s color math.&lt;br /&gt;
|-&lt;br /&gt;
| Kevin&#039;s Lunar Magic VRAM optimization (&amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;) || Integrates Kevin&#039;s optimization for Lunar Magic VRAM updates and moves some of its processing out of NMI. Use this version instead of installing the original patch separately. Once installed, it must not be uninstalled: doing so can break the ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Status bar optimization (&amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt;) || Reduces the original status bar&#039;s NMI work. Incompatible with resources that replace or modify it, such as custom status bars or patches that remove it.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For options that may conflict with other resources and the RAM used by the system, see [[#Compatibility|Compatibility]].&lt;br /&gt;
&lt;br /&gt;
Some features depend on others: &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; requires &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; requires &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; requires both graphics and palette changes; and &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; requires &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Quick installation guide:&#039;&#039;&#039; [[Dynamic_Xtreme_Quick_Start|Quick Start]]&lt;br /&gt;
&lt;br /&gt;
== Tools and support ==&lt;br /&gt;
&lt;br /&gt;
Pending&lt;br /&gt;
&lt;br /&gt;
== Files and formats ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Related article:&#039;&#039;&#039; [[Dynamic_Xtreme_files_and_formats|Dynamic Xtreme files and formats]]&lt;br /&gt;
&lt;br /&gt;
== Dynamic sprite creation guide ==&lt;br /&gt;
&lt;br /&gt;
To learn how to prepare, program, load, and draw a dynamic sprite, see the [[Dynamic_Xtreme_sprite_creation_guide|Dynamic Xtreme dynamic sprite creation guide]].&lt;br /&gt;
&lt;br /&gt;
== Dynamic Xtreme with UberASM ==&lt;br /&gt;
&lt;br /&gt;
The [[Dynamic_Xtreme_UberASM_guide|Dynamic Xtreme UberASM guide]] shows how to reserve palettes, configure dynamic sprite space and the per-frame data limit, create animations, change player graphics, and apply palette effects.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
&lt;br /&gt;
The [[Dynamic_Xtreme_ASM_API|ASM API reference]] explains how to use Dynamic Xtreme&#039;s variables, defines, routines, and macros. It covers each call&#039;s inputs and results, with examples for poses, drawing, palettes, color effects, and graphics transfers, as well as multiplication and division macros.&lt;br /&gt;
&lt;br /&gt;
== How the system works ==&lt;br /&gt;
&lt;br /&gt;
The article on [[Dynamic_Xtreme_internal_workings|Dynamic Xtreme&#039;s internal workings]] explains the organization of NMI and game modes, graphics and palette loading, pose drawing, optimizations, the dynamic pose cache, and palette effects.&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
In general, features without installer warnings do not usually have compatibility problems with other resources. These are:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This does not guarantee that every resource combination will work: two pieces of code may still use the same RAM, the same VRAM space, or modify the same game routine. Also, &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; requires &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, so the latter&#039;s restrictions still apply.&lt;br /&gt;
&lt;br /&gt;
=== Features with compatibility restrictions ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Optional feature !! Possible conflicts and what to do&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; || May conflict with &#039;&#039;&#039;LX5&#039;s Powerups&#039;&#039;&#039;, &#039;&#039;&#039;Player 8x8 tiles DMAer&#039;&#039;&#039;, &#039;&#039;&#039;Player 32x32&#039;&#039;&#039;, and other systems that replace player graphics or palette loading. &#039;&#039;&#039;Player Revolution&#039;&#039;&#039; is compatible. If your player system needs those original routines, leave this option disabled; you must also disable &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; || Depends on &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; and inherits its compatibility restrictions, even though it has no separate warning. If a resource is incompatible with &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, enabling only &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; cannot avoid the conflict: leave both disabled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt; || Incompatible with resources that modify, replace, or remove the original status bar, such as &#039;&#039;&#039;LX5&#039;s DKC Style Status Bar&#039;&#039;&#039;, &#039;&#039;&#039;Minimalistic Status Bar&#039;&#039;&#039;, and &#039;&#039;&#039;Nuke Status Bar&#039;&#039;&#039;. Leave this optimization disabled if you use one of them.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt; || Integrates Kevin&#039;s Lunar Magic VRAM optimization patch: use this version instead of installing the original separately. Its warning also states that it &#039;&#039;&#039;must not be uninstalled after installation&#039;&#039;&#039;, because doing so can break the ROM. To revert it, restore a backup made before installation.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These features are optional: leave a conflicting feature disabled and continue using Dynamic Xtreme&#039;s other systems, respecting their dependencies. Disabling an option does not undo another patch&#039;s changes or remove the uninstall restriction on &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== RAM usage ===&lt;br /&gt;
&lt;br /&gt;
The main addresses are configured in &amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt; inside the Dynamic Xtreme directory. In the repository, this is &amp;lt;code&amp;gt;DynamicXtremeLibrary/ASM/DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The space used depends on the enabled features and whether the ROM uses SA-1. The following ranges include both endpoints and were calculated with &#039;&#039;&#039;all features that reserve RAM enabled&#039;&#039;&#039;, &amp;lt;code&amp;gt;!VRAMTransferSize = 64&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!CGRAMTransferSize = 64&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuration !! &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; block !! Size !! &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; block !! Size&lt;br /&gt;
|-&lt;br /&gt;
| LoROM with &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2000–$7E2500&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7E2800–$7E3608&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM without &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB440–$7FB940&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7F9C80–$7FAA88&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C000–$40C47E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$047F&amp;lt;/code&amp;gt;: 1151 bytes || &amp;lt;code&amp;gt;$418AFF–$419907&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two internal blocks total &#039;&#039;&#039;4874 bytes on LoROM&#039;&#039;&#039; and &#039;&#039;&#039;4744 bytes on SA-1&#039;&#039;&#039;. The difference comes from the drawing system&#039;s 130 bytes, which are reserved only on LoROM. The gap between the blocks is not automatically occupied.&lt;br /&gt;
&lt;br /&gt;
Disabling a feature removes its conditional reservations and shifts the addresses that follow. Increasing &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; also increases their table sizes.&lt;br /&gt;
&lt;br /&gt;
==== Sprite tables ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; &#039;&#039;&#039;are not available for your own variables&#039;&#039;&#039;: the sprite tables from &amp;lt;code&amp;gt;DynamicXSpritesTables.asm&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;MoreSpriteMiscs.asm&amp;lt;/code&amp;gt; begin there. You must also reserve them when using those resources.&lt;br /&gt;
&lt;br /&gt;
With the same configuration as the table above, their ranges are:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuration !! Tables starting at &amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; !! Size !! Tables starting at &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; !! Size&lt;br /&gt;
|-&lt;br /&gt;
| LoROM with &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2501–$7E26EC&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7E3609–$7E3824&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM without &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB941–$7FBB2C&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7FAC82–$7FAE9D&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C47F–$40C6D8&amp;lt;/code&amp;gt; || 602 bytes || &amp;lt;code&amp;gt;$419908–$419BCD&amp;lt;/code&amp;gt; || 710 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Including these tables, the described space totals &#039;&#039;&#039;5906 bytes on LoROM&#039;&#039;&#039; and &#039;&#039;&#039;6056 bytes on SA-1&#039;&#039;&#039;. Tables are calculated for 12 normal sprites on LoROM and 22 on SA-1, plus the corresponding cluster, extended, and smoke slots.&lt;br /&gt;
&lt;br /&gt;
Normally, &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; starts immediately after the second internal block. On LoROM without &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, it is placed separately using &amp;lt;code&amp;gt;!Variables3 = $7FAC82&amp;lt;/code&amp;gt;, so its tables do not immediately follow &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme also uses the existing fixed color and palette mirrors: &amp;lt;code&amp;gt;$7E0701&amp;lt;/code&amp;gt; (2 bytes) and &amp;lt;code&amp;gt;$7E0703&amp;lt;/code&amp;gt; (512 bytes) on LoROM. Their declared SA-1 addresses are &amp;lt;code&amp;gt;$406701&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$006703&amp;lt;/code&amp;gt;. These are neither additional reservations within the blocks above nor free addresses for your code.&lt;br /&gt;
&lt;br /&gt;
==== Relocating RAM to resolve a conflict ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; relocating these variables requires knowing which address to choose and accounting for the full memory footprint. A free starting address is not enough: the entire block must fit, and the routines must be able to access it. If you are unfamiliar with this, consult someone experienced before changing the addresses.&lt;br /&gt;
&lt;br /&gt;
If another resource uses any of these areas, you can edit &#039;&#039;&#039;&amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt;&#039;&#039;&#039; to make Dynamic Xtreme use other available space in your ROM hack.&lt;br /&gt;
&lt;br /&gt;
* Change &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; in the configuration matching your ROM: LoROM with &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, LoROM without it, or SA-1.&lt;br /&gt;
* On LoROM without &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, also check &amp;lt;code&amp;gt;!Variables3&amp;lt;/code&amp;gt;, which determines where the &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; tables begin.&lt;br /&gt;
* Reserve enough space for the entire block and the sprite tables that follow. A free first address alone is not enough.&lt;br /&gt;
* Respect the memory map and the banks required by the routines. Not every free address works with every type of access.&lt;br /&gt;
* After changing the addresses, reinstall Dynamic Xtreme and reinsert PIXI, UberASM, and any other resources that use its defines.&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, Dynamic Xtreme uses the RAM recovered by relocating the original graphics; do not share it with other resources without checking which part is used. Without that option, the alternative addresses may overlap those of other common resources. SA-1 uses its own addresses and disables &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Edit the file in the &#039;&#039;&#039;ASM&#039;&#039;&#039; directory, not the generated copies in &amp;lt;code&amp;gt;ExtraDefines&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Patch/ExtraDefines&amp;lt;/code&amp;gt;: those copies are regenerated during installation.&lt;br /&gt;
&lt;br /&gt;
== Resources made with Dynamic Xtreme ==&lt;br /&gt;
&lt;br /&gt;
Resources developed for Dynamic Xtreme are not usually published on traditional sites such as SMW Central, because many depend directly on the framework and its advanced systems.&lt;br /&gt;
&lt;br /&gt;
Instead, Dynamic Xtreme resources, examples, systems, and related projects are mainly collected at:&lt;br /&gt;
&lt;br /&gt;
https://snestorage.dev&lt;br /&gt;
&lt;br /&gt;
There you can find sprites, player systems, graphical effects, technical examples, and other resources designed specifically for Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aims to modernize and simplify dynamic systems in Super Mario World, offering more flexible, powerful, and accessible tools while retaining compatibility and advanced control.&lt;br /&gt;
&lt;br /&gt;
The project continues to evolve with new optimizations, formats, and tools for both experienced users and people just starting to work with dynamic graphics on SNES.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme&#039;s main aim is to support increasingly complex resources and systems while keeping the workflow cleaner, easier to maintain, and more accessible to the community.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21402</id>
		<title>es/Dynamic Xtreme</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21402"/>
		<updated>2026-10-25T22:16:11Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es una herramienta de soporte dinámico avanzada para Super Mario World en el SNES, creada por [[User:Anonimzwx|Anonimzwx]] y sucesora de Dynamic Z y Dynamic X. Desarrollada para la comunidad de ROM hacking, permite realizar cambios gráficos y de paletas en tiempo real durante la ejecución del juego. La herramienta se centra en ofrecer un sistema completo y flexible de gráficos dinámicos, con énfasis en el rendimiento y la modularidad.&lt;br /&gt;
&lt;br /&gt;
Un sprite dinámico carga recursos, como gráficos o paletas, en tiempo real durante el juego. En cambio, un sprite estático utiliza los recursos que ya estaban cargados al comenzar el nivel.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme no rompe los límites del hardware de SNES: trabaja dentro de ellos y optimiza el uso de la memoria y las transferencias para reducir su impacto y hacer que sean mucho menos perceptibles durante el juego.&lt;br /&gt;
&lt;br /&gt;
Entre sus características principales se incluyen:&lt;br /&gt;
* Cambios gráficos y de paleta en tiempo real (on-the-fly).&lt;br /&gt;
* El sistema de Dynamic Sprite más potente y flexible disponible para Super Mario World.&lt;br /&gt;
* Advanced Drawing System, que permite dibujar cualquier frame registrado en pantalla con control total sobre prioridad, capa, desplazamiento (offset) y propiedades.&lt;br /&gt;
* Efectos de paleta avanzados, que incluyen modificación en tiempo real mediante tono (hue), saturación, brillo, fusión de colores, transiciones suaves y control individual de canales RGB y HSL.&lt;br /&gt;
* Reemplazo completo de gráficos y paletas del jugador, compatible con cualquier tamaño de Mario, cualquier cantidad de frames y cualquier estilo de animación.&lt;br /&gt;
* Reemplazo de gráficos de Yoshi usando un layout como el del juego original.&lt;br /&gt;
* Optimizaciones intensivas en el NMI-handler para maximizar el rendimiento.&lt;br /&gt;
&lt;br /&gt;
Las funciones de Dynamic Xtreme se seleccionan durante la instalación para utilizar solo las que necesita el proyecto. Algunas tienen dependencias, problemas de compatibilidad o restricciones para desinstalarlas; revisa las advertencias de cada opción. La herramienta fue creada con el objetivo de facilitar la implementación de efectos visuales complejos en hacks de Super Mario World manteniendo un alto nivel de compatibilidad y estabilidad.&lt;br /&gt;
&lt;br /&gt;
== Objetivos del proyecto ==&lt;br /&gt;
&lt;br /&gt;
El principal objetivo de Dynamic Xtreme es facilitar el uso de sprites dinámicos y ofrecer un soporte completo para cambios de gráficos, paletas y tilemaps en tiempo real.&lt;br /&gt;
&lt;br /&gt;
El proyecto busca aprovechar al máximo el potencial del SNES sin requerir que el usuario tenga conocimientos avanzados sobre el hardware interno de la consola. Muchos sistemas dinámicos tradicionales suelen ser complejos y dependen fuertemente de conceptos técnicos como VRAM, CGRAM, OAM o DMA. Dynamic Xtreme intenta abstraer gran parte de esa complejidad mediante herramientas y formatos más modernos, legibles y fáciles de utilizar.&lt;br /&gt;
&lt;br /&gt;
Otro de los objetivos principales del proyecto es mantener un alto rendimiento incluso en situaciones visualmente complejas, permitiendo el uso intensivo de gráficos dinámicos, efectos de paletas y sistemas avanzados de renderizado sin comprometer innecesariamente la performance.&lt;br /&gt;
&lt;br /&gt;
Además, Dynamic Xtreme busca que los sprites dinámicos puedan utilizarse de una forma tan natural y sencilla como si fueran sprites normales. La idea es que las personas enfocadas en level design o creación de contenido no necesiten preocuparse constantemente por las limitaciones técnicas internas del sistema y puedan trabajar con recursos dinámicos de forma transparente y práctica.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades ==&lt;br /&gt;
&lt;br /&gt;
Durante la instalación puedes elegir qué funcionalidades habilitar. Los nombres entre paréntesis corresponden a las opciones del instalador y de &amp;lt;code&amp;gt;Settings.json&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Gráficos, poses y paletas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de gráficos (&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;) || Permite cargar gráficos durante el juego. Es la base para las animaciones de tiles, los cambios de gráficos del nivel y las poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de paletas (&amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;) || Permite cargar y administrar paletas durante el juego. Incluye la asignación automática de paletas para que los sprites puedan compartir los mismos colores sin cargarlos varias veces.&lt;br /&gt;
|-&lt;br /&gt;
| Poses dinámicas (&amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;) || Administra el espacio de VRAM como una caché de poses: reutiliza las que ya están cargadas, permite compartirlas entre entidades y elige cuáles reemplazar cuando hace falta espacio. Así evita cargas innecesarias.&lt;br /&gt;
|-&lt;br /&gt;
| Dibujo de poses (&amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;) || Dibuja las poses definidas en archivos DrawInfo, tanto dinámicas como estáticas. Permite controlar sus tiles, posición, volteo, paleta y prioridad de dibujo.&lt;br /&gt;
|-&lt;br /&gt;
| Efectos de paleta (&amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;) || Permite cambiar colores mediante efectos RGB y HSL: teñir paletas, modificar tono, saturación o luminosidad, y realizar transiciones entre paletas. Pueden aplicarse a recursos individuales o como un efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La carga de poses dinámicas y el dibujo son sistemas separados: puedes dibujar una pose estática sin cargar sus gráficos dinámicamente.&lt;br /&gt;
&lt;br /&gt;
=== Jugador y Yoshi ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Funciones del jugador (&amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos y paletas del jugador y adaptar su dibujo y carga de poses a sistemas personalizados. También permite ocultarlo o desactivar sus cargas dinámicas. Puede entrar en conflicto con parches que modifican los gráficos o paletas del jugador; revisa la advertencia del instalador antes de habilitarla.&lt;br /&gt;
|-&lt;br /&gt;
| Funciones de Yoshi (&amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos de Yoshi manteniendo la organización de sus poses originales. Requiere &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memoria y optimizaciones ===&lt;br /&gt;
&lt;br /&gt;
Estas opciones reorganizan parte del trabajo del juego para dejar más tiempo disponible para las cargas de gráficos y paletas. NMI es la rutina que realiza las actualizaciones de pantalla durante la pausa entre un frame y el siguiente.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Liberar el área &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;) || En ROMs sin SA-1, evita mantener en RAM ciertos gráficos originales del jugador, Yoshi y animaciones, y permite leerlos desde ROM. Dynamic Xtreme utiliza el espacio recuperado para sus variables internas; no queda libre para usarlo sin reservar. Esta opción no se aplica a ROMs con SA-1.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del control (&amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;) || Mueve el procesamiento del control fuera de NMI para dejar más tiempo disponible para las actualizaciones de pantalla.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del color fijo (&amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI relacionado con la actualización del color fijo que utiliza el juego para sus mezclas de color.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de VRAM de Lunar Magic de Kevin (&amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;) || Integra la optimización de Kevin para las actualizaciones de VRAM de Lunar Magic y mueve parte de su procesamiento fuera de NMI. Utiliza esta versión en lugar del parche original por separado. Una vez instalada, no debe desinstalarse: hacerlo puede dañar el funcionamiento de la ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de la barra de estado (&amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI de la barra de estado original. No es compatible con recursos que la reemplazan o modifican, como barras de estado personalizadas o parches que la eliminan.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para revisar qué opciones pueden entrar en conflicto con otros recursos y qué RAM utiliza el sistema, consulta [[#Compatibilidad|Compatibilidad]].&lt;br /&gt;
&lt;br /&gt;
Algunas funcionalidades necesitan otras: &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; necesita ambas opciones de cambios gráficos y de paletas; y &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guía rápida de instalación:&#039;&#039;&#039; [[es/Dynamic_Xtreme_Quick_Start|Quick Start]]&lt;br /&gt;
&lt;br /&gt;
== Herramientas y Soporte ==&lt;br /&gt;
&lt;br /&gt;
Pendiente&lt;br /&gt;
&lt;br /&gt;
== Archivos y formatos ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Artículo relacionado:&#039;&#039;&#039; [[es/Dynamic_Xtreme_files_and_formats|Archivos y Formatos de Dynamic Xtreme]]&lt;br /&gt;
&lt;br /&gt;
== Guía de creación de sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Para aprender a preparar, programar, cargar y dibujar un sprite dinámico, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites dinámicos con Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
== Dynamic Xtreme con UberASM ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_UberASM_guide|guía de Dynamic Xtreme con UberASM]] muestra cómo reservar paletas, configurar el espacio para sprites dinámicos y el límite de datos por frame, crear animaciones, cambiar gráficos del jugador y aplicar efectos de paleta.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]] explica cómo utilizar las variables, los defines, las rutinas y las macros de Dynamic Xtreme. Incluye los datos que necesita cada llamada, sus resultados y ejemplos de uso para trabajar con poses, dibujo, paletas, efectos de color y transferencias de gráficos, además de las macros de multiplicación y división.&lt;br /&gt;
&lt;br /&gt;
== Funcionamiento interno del sistema ==&lt;br /&gt;
&lt;br /&gt;
El artículo sobre el [[es/Dynamic_Xtreme_internal_workings|funcionamiento interno de Dynamic Xtreme]] explica cómo se organizan NMI y los game modes, las cargas de gráficos y paletas, el dibujo de poses, las optimizaciones, la caché de poses dinámicas y los efectos de paleta.&lt;br /&gt;
&lt;br /&gt;
== Compatibilidad ==&lt;br /&gt;
&lt;br /&gt;
En general, las funcionalidades que no muestran warnings en el instalador no suelen presentar problemas de incompatibilidad con otros recursos. Estas son:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esto no garantiza que cualquier combinación de recursos funcione: dos códigos todavía pueden utilizar la misma RAM, el mismo espacio de VRAM o modificar la misma rutina del juego. Además, &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, por lo que también debes considerar las restricciones de esta última.&lt;br /&gt;
&lt;br /&gt;
=== Funcionalidades con restricciones de compatibilidad ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad opcional !! Posibles conflictos y qué hacer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; || Puede entrar en conflicto con &#039;&#039;&#039;LX5&#039;s Powerups&#039;&#039;&#039;, &#039;&#039;&#039;Player 8x8 tiles DMAer&#039;&#039;&#039;, &#039;&#039;&#039;Player 32x32&#039;&#039;&#039; y otros sistemas que reemplazan la carga de gráficos o paletas del jugador. &#039;&#039;&#039;Player Revolution&#039;&#039;&#039; sí es compatible. Si tu sistema de jugador necesita esas rutinas originales, deja esta opción deshabilitada; también tendrás que deshabilitar &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; || Depende de &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y hereda sus restricciones de compatibilidad, aunque no muestre un warning propio. Si otro recurso es incompatible con &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, no puedes evitar ese conflicto habilitando únicamente &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;: debes dejar ambas deshabilitadas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt; || No es compatible con recursos que modifican, reemplazan o eliminan la barra de estado original, como &#039;&#039;&#039;LX5&#039;s DKC Style Status Bar&#039;&#039;&#039;, &#039;&#039;&#039;Minimalistic Status Bar&#039;&#039;&#039; y &#039;&#039;&#039;Nuke Status Bar&#039;&#039;&#039;. Si utilizas uno de ellos, deja esta optimización deshabilitada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt; || Integra el parche de optimización de VRAM de Lunar Magic de Kevin: utiliza esta versión en lugar del parche original por separado. Su warning también indica que &#039;&#039;&#039;no debe desinstalarse después de instalarla&#039;&#039;&#039;, porque hacerlo puede romper el funcionamiento de la ROM. Si necesitas revertirla, restaura una copia de seguridad anterior a su instalación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas funcionalidades son opcionales: puedes dejar deshabilitada la que entra en conflicto y seguir utilizando los demás sistemas de Dynamic Xtreme, respetando sus dependencias. Deshabilitar una opción no deshace los cambios de otro parche ni elimina la restricción de desinstalación de &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Espacios de RAM utilizados ===&lt;br /&gt;
&lt;br /&gt;
Las direcciones principales se configuran en &amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt;, dentro de la carpeta de Dynamic Xtreme. En el repositorio, ese archivo corresponde a &amp;lt;code&amp;gt;DynamicXtremeLibrary/ASM/DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El espacio utilizado depende de las funcionalidades habilitadas y de si la ROM utiliza SA-1. Los siguientes rangos incluyen el primer y el último byte y están calculados con &#039;&#039;&#039;todas las funcionalidades que reservan RAM habilitadas&#039;&#039;&#039;, &amp;lt;code&amp;gt;!VRAMTransferSize = 64&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!CGRAMTransferSize = 64&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuración !! Bloque &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; !! Tamaño !! Bloque &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; !! Tamaño&lt;br /&gt;
|-&lt;br /&gt;
| LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2000–$7E2500&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7E2800–$7E3608&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB440–$7FB940&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7F9C80–$7FAA88&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C000–$40C47E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$047F&amp;lt;/code&amp;gt;: 1151 bytes || &amp;lt;code&amp;gt;$418AFF–$419907&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los dos bloques internos suman &#039;&#039;&#039;4874 bytes en LoROM&#039;&#039;&#039; y &#039;&#039;&#039;4744 bytes en SA-1&#039;&#039;&#039;. La diferencia se debe a los 130 bytes del sistema de dibujo que solo se reservan en LoROM. No se ocupa automáticamente el espacio que queda entre los bloques.&lt;br /&gt;
&lt;br /&gt;
Al deshabilitar una funcionalidad se eliminan sus reservas condicionales y cambian las direcciones posteriores. Aumentar &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; también aumenta el tamaño de sus tablas.&lt;br /&gt;
&lt;br /&gt;
==== Tablas utilizadas por los sprites ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; &#039;&#039;&#039;no son espacios disponibles para escribir variables propias&#039;&#039;&#039;: a partir de esas posiciones se ubican las tablas de sprites de &amp;lt;code&amp;gt;DynamicXSpritesTables.asm&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;MoreSpriteMiscs.asm&amp;lt;/code&amp;gt;. También debes reservarlas si utilizas esos recursos.&lt;br /&gt;
&lt;br /&gt;
Con la misma configuración de la tabla anterior, sus rangos son:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuración !! Tablas desde &amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; !! Tamaño !! Tablas desde &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; !! Tamaño&lt;br /&gt;
|-&lt;br /&gt;
| LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2501–$7E26EC&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7E3609–$7E3824&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB941–$7FBB2C&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7FAC82–$7FAE9D&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C47F–$40C6D8&amp;lt;/code&amp;gt; || 602 bytes || &amp;lt;code&amp;gt;$419908–$419BCD&amp;lt;/code&amp;gt; || 710 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Incluyendo estas tablas, el espacio descrito suma &#039;&#039;&#039;5906 bytes en LoROM&#039;&#039;&#039; y &#039;&#039;&#039;6056 bytes en SA-1&#039;&#039;&#039;. Las tablas se calculan para 12 sprites normales en LoROM y 22 en SA-1, además de los slots de cluster, extended y smoke correspondientes.&lt;br /&gt;
&lt;br /&gt;
Normalmente, &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; comienza justo después del segundo bloque interno. En LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; se coloca por separado mediante &amp;lt;code&amp;gt;!Variables3 = $7FAC82&amp;lt;/code&amp;gt;; por eso sus tablas no empiezan inmediatamente después de &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme también utiliza los espejos existentes del color fijo y de la paleta: &amp;lt;code&amp;gt;$7E0701&amp;lt;/code&amp;gt; (2 bytes) y &amp;lt;code&amp;gt;$7E0703&amp;lt;/code&amp;gt; (512 bytes) en LoROM. En SA-1 sus direcciones declaradas son &amp;lt;code&amp;gt;$406701&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$006703&amp;lt;/code&amp;gt;. No son reservas adicionales dentro de los bloques anteriores ni direcciones libres para tus códigos.&lt;br /&gt;
&lt;br /&gt;
==== Reubicar la RAM si hay un conflicto ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Advertencia:&#039;&#039;&#039; para reubicar estas variables debes saber qué dirección elegir y considerar el tamaño completo del espacio de memoria que utiliza el sistema. No basta con que una dirección esté libre: debe haber espacio suficiente y las rutinas deben poder acceder a él. Si no tienes conocimientos sobre esto, consulta con alguien que los tenga antes de modificar las direcciones.&lt;br /&gt;
&lt;br /&gt;
Si otro recurso utiliza alguno de estos espacios, puedes modificar &#039;&#039;&#039;&amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt;&#039;&#039;&#039; para hacer que Dynamic Xtreme utilice otras zonas disponibles de tu romhack.&lt;br /&gt;
&lt;br /&gt;
* Cambia &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; en la configuración correspondiente a tu ROM: LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, LoROM sin esa opción o SA-1.&lt;br /&gt;
* En LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, revisa también &amp;lt;code&amp;gt;!Variables3&amp;lt;/code&amp;gt;, que determina dónde empiezan las tablas de &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Reserva espacio suficiente para el bloque completo y las tablas de sprites que le siguen. No basta con que la primera dirección esté libre.&lt;br /&gt;
* Respeta el mapa de memoria y los bancos que necesitan las rutinas. No cualquier dirección libre sirve para cualquier acceso.&lt;br /&gt;
* Después de cambiar las direcciones, reinstala Dynamic Xtreme y vuelve a insertar PIXI, UberASM y los demás recursos que utilicen sus defines.&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, Dynamic Xtreme aprovecha el área de RAM que recupera al reubicar los gráficos originales; no la compartas con otros recursos sin comprobar qué parte utiliza. Sin esa opción, las direcciones alternativas pueden coincidir con las de otros recursos habituales. SA-1 utiliza sus propias direcciones y desactiva &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Modifica el archivo de la carpeta &#039;&#039;&#039;ASM&#039;&#039;&#039;, no las copias generadas en &amp;lt;code&amp;gt;ExtraDefines&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;Patch/ExtraDefines&amp;lt;/code&amp;gt;: esas copias se regeneran durante la instalación.&lt;br /&gt;
&lt;br /&gt;
== Recursos hechos con Dynamic Xtreme ==&lt;br /&gt;
&lt;br /&gt;
La mayoría de los recursos desarrollados para Dynamic Xtreme no suelen publicarse en sitios tradicionales como SMW Central debido a que muchos de ellos dependen directamente del framework y sus sistemas avanzados.&lt;br /&gt;
&lt;br /&gt;
En su lugar, los recursos, ejemplos, sistemas y proyectos relacionados con Dynamic Xtreme se encuentran recopilados principalmente en:&lt;br /&gt;
&lt;br /&gt;
https://snestorage.dev&lt;br /&gt;
&lt;br /&gt;
Allí es posible encontrar sprites, sistemas de jugador, efectos gráficos, ejemplos técnicos y otros recursos diseñados específicamente para trabajar con Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
== Conclusión ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es un proyecto orientado a modernizar y simplificar el uso de sistemas dinámicos en Super Mario World, ofreciendo herramientas más flexibles, potentes y fáciles de utilizar sin perder compatibilidad ni control avanzado.&lt;br /&gt;
&lt;br /&gt;
El proyecto continúa evolucionando constantemente con nuevas optimizaciones, formatos y herramientas orientadas tanto a usuarios avanzados como a personas que recién comienzan a trabajar con gráficos dinámicos en SNES.&lt;br /&gt;
&lt;br /&gt;
La intención principal de Dynamic Xtreme es permitir la creación de recursos y sistemas cada vez más complejos, manteniendo al mismo tiempo un workflow más limpio, mantenible y accesible para la comunidad.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21401</id>
		<title>es/Dynamic Xtreme</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21401"/>
		<updated>2026-10-25T22:14:47Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es una herramienta de soporte dinámico avanzada para Super Mario World en el SNES, creada por anonimzwx y sucesora de Dynamic Z y Dynamic X. Desarrollada para la comunidad de ROM hacking, permite realizar cambios gráficos y de paletas en tiempo real durante la ejecución del juego. La herramienta se centra en ofrecer un sistema completo y flexible de gráficos dinámicos, con énfasis en el rendimiento y la modularidad.&lt;br /&gt;
&lt;br /&gt;
Un sprite dinámico carga recursos, como gráficos o paletas, en tiempo real durante el juego. En cambio, un sprite estático utiliza los recursos que ya estaban cargados al comenzar el nivel.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme no rompe los límites del hardware de SNES: trabaja dentro de ellos y optimiza el uso de la memoria y las transferencias para reducir su impacto y hacer que sean mucho menos perceptibles durante el juego.&lt;br /&gt;
&lt;br /&gt;
Entre sus características principales se incluyen:&lt;br /&gt;
* Cambios gráficos y de paleta en tiempo real (on-the-fly).&lt;br /&gt;
* El sistema de Dynamic Sprite más potente y flexible disponible para Super Mario World.&lt;br /&gt;
* Advanced Drawing System, que permite dibujar cualquier frame registrado en pantalla con control total sobre prioridad, capa, desplazamiento (offset) y propiedades.&lt;br /&gt;
* Efectos de paleta avanzados, que incluyen modificación en tiempo real mediante tono (hue), saturación, brillo, fusión de colores, transiciones suaves y control individual de canales RGB y HSL.&lt;br /&gt;
* Reemplazo completo de gráficos y paletas del jugador, compatible con cualquier tamaño de Mario, cualquier cantidad de frames y cualquier estilo de animación.&lt;br /&gt;
* Reemplazo de gráficos de Yoshi usando un layout como el del juego original.&lt;br /&gt;
* Optimizaciones intensivas en el NMI-handler para maximizar el rendimiento.&lt;br /&gt;
&lt;br /&gt;
Las funciones de Dynamic Xtreme se seleccionan durante la instalación para utilizar solo las que necesita el proyecto. Algunas tienen dependencias, problemas de compatibilidad o restricciones para desinstalarlas; revisa las advertencias de cada opción. La herramienta fue creada con el objetivo de facilitar la implementación de efectos visuales complejos en hacks de Super Mario World manteniendo un alto nivel de compatibilidad y estabilidad.&lt;br /&gt;
&lt;br /&gt;
== Objetivos del proyecto ==&lt;br /&gt;
&lt;br /&gt;
El principal objetivo de Dynamic Xtreme es facilitar el uso de sprites dinámicos y ofrecer un soporte completo para cambios de gráficos, paletas y tilemaps en tiempo real.&lt;br /&gt;
&lt;br /&gt;
El proyecto busca aprovechar al máximo el potencial del SNES sin requerir que el usuario tenga conocimientos avanzados sobre el hardware interno de la consola. Muchos sistemas dinámicos tradicionales suelen ser complejos y dependen fuertemente de conceptos técnicos como VRAM, CGRAM, OAM o DMA. Dynamic Xtreme intenta abstraer gran parte de esa complejidad mediante herramientas y formatos más modernos, legibles y fáciles de utilizar.&lt;br /&gt;
&lt;br /&gt;
Otro de los objetivos principales del proyecto es mantener un alto rendimiento incluso en situaciones visualmente complejas, permitiendo el uso intensivo de gráficos dinámicos, efectos de paletas y sistemas avanzados de renderizado sin comprometer innecesariamente la performance.&lt;br /&gt;
&lt;br /&gt;
Además, Dynamic Xtreme busca que los sprites dinámicos puedan utilizarse de una forma tan natural y sencilla como si fueran sprites normales. La idea es que las personas enfocadas en level design o creación de contenido no necesiten preocuparse constantemente por las limitaciones técnicas internas del sistema y puedan trabajar con recursos dinámicos de forma transparente y práctica.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades ==&lt;br /&gt;
&lt;br /&gt;
Durante la instalación puedes elegir qué funcionalidades habilitar. Los nombres entre paréntesis corresponden a las opciones del instalador y de &amp;lt;code&amp;gt;Settings.json&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Gráficos, poses y paletas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de gráficos (&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;) || Permite cargar gráficos durante el juego. Es la base para las animaciones de tiles, los cambios de gráficos del nivel y las poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de paletas (&amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;) || Permite cargar y administrar paletas durante el juego. Incluye la asignación automática de paletas para que los sprites puedan compartir los mismos colores sin cargarlos varias veces.&lt;br /&gt;
|-&lt;br /&gt;
| Poses dinámicas (&amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;) || Administra el espacio de VRAM como una caché de poses: reutiliza las que ya están cargadas, permite compartirlas entre entidades y elige cuáles reemplazar cuando hace falta espacio. Así evita cargas innecesarias.&lt;br /&gt;
|-&lt;br /&gt;
| Dibujo de poses (&amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;) || Dibuja las poses definidas en archivos DrawInfo, tanto dinámicas como estáticas. Permite controlar sus tiles, posición, volteo, paleta y prioridad de dibujo.&lt;br /&gt;
|-&lt;br /&gt;
| Efectos de paleta (&amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;) || Permite cambiar colores mediante efectos RGB y HSL: teñir paletas, modificar tono, saturación o luminosidad, y realizar transiciones entre paletas. Pueden aplicarse a recursos individuales o como un efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La carga de poses dinámicas y el dibujo son sistemas separados: puedes dibujar una pose estática sin cargar sus gráficos dinámicamente.&lt;br /&gt;
&lt;br /&gt;
=== Jugador y Yoshi ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Funciones del jugador (&amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos y paletas del jugador y adaptar su dibujo y carga de poses a sistemas personalizados. También permite ocultarlo o desactivar sus cargas dinámicas. Puede entrar en conflicto con parches que modifican los gráficos o paletas del jugador; revisa la advertencia del instalador antes de habilitarla.&lt;br /&gt;
|-&lt;br /&gt;
| Funciones de Yoshi (&amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos de Yoshi manteniendo la organización de sus poses originales. Requiere &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memoria y optimizaciones ===&lt;br /&gt;
&lt;br /&gt;
Estas opciones reorganizan parte del trabajo del juego para dejar más tiempo disponible para las cargas de gráficos y paletas. NMI es la rutina que realiza las actualizaciones de pantalla durante la pausa entre un frame y el siguiente.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Liberar el área &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;) || En ROMs sin SA-1, evita mantener en RAM ciertos gráficos originales del jugador, Yoshi y animaciones, y permite leerlos desde ROM. Dynamic Xtreme utiliza el espacio recuperado para sus variables internas; no queda libre para usarlo sin reservar. Esta opción no se aplica a ROMs con SA-1.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del control (&amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;) || Mueve el procesamiento del control fuera de NMI para dejar más tiempo disponible para las actualizaciones de pantalla.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del color fijo (&amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI relacionado con la actualización del color fijo que utiliza el juego para sus mezclas de color.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de VRAM de Lunar Magic de Kevin (&amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;) || Integra la optimización de Kevin para las actualizaciones de VRAM de Lunar Magic y mueve parte de su procesamiento fuera de NMI. Utiliza esta versión en lugar del parche original por separado. Una vez instalada, no debe desinstalarse: hacerlo puede dañar el funcionamiento de la ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de la barra de estado (&amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI de la barra de estado original. No es compatible con recursos que la reemplazan o modifican, como barras de estado personalizadas o parches que la eliminan.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para revisar qué opciones pueden entrar en conflicto con otros recursos y qué RAM utiliza el sistema, consulta [[#Compatibilidad|Compatibilidad]].&lt;br /&gt;
&lt;br /&gt;
Algunas funcionalidades necesitan otras: &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; necesita ambas opciones de cambios gráficos y de paletas; y &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guía rápida de instalación:&#039;&#039;&#039; [[es/Dynamic_Xtreme_Quick_Start|Quick Start]]&lt;br /&gt;
&lt;br /&gt;
== Herramientas y Soporte ==&lt;br /&gt;
&lt;br /&gt;
Pendiente&lt;br /&gt;
&lt;br /&gt;
== Archivos y formatos ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Artículo relacionado:&#039;&#039;&#039; [[es/Dynamic_Xtreme_files_and_formats|Archivos y Formatos de Dynamic Xtreme]]&lt;br /&gt;
&lt;br /&gt;
== Guía de creación de sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Para aprender a preparar, programar, cargar y dibujar un sprite dinámico, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites dinámicos con Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
== Dynamic Xtreme con UberASM ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_UberASM_guide|guía de Dynamic Xtreme con UberASM]] muestra cómo reservar paletas, configurar el espacio para sprites dinámicos y el límite de datos por frame, crear animaciones, cambiar gráficos del jugador y aplicar efectos de paleta.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]] explica cómo utilizar las variables, los defines, las rutinas y las macros de Dynamic Xtreme. Incluye los datos que necesita cada llamada, sus resultados y ejemplos de uso para trabajar con poses, dibujo, paletas, efectos de color y transferencias de gráficos, además de las macros de multiplicación y división.&lt;br /&gt;
&lt;br /&gt;
== Funcionamiento interno del sistema ==&lt;br /&gt;
&lt;br /&gt;
El artículo sobre el [[es/Dynamic_Xtreme_internal_workings|funcionamiento interno de Dynamic Xtreme]] explica cómo se organizan NMI y los game modes, las cargas de gráficos y paletas, el dibujo de poses, las optimizaciones, la caché de poses dinámicas y los efectos de paleta.&lt;br /&gt;
&lt;br /&gt;
== Compatibilidad ==&lt;br /&gt;
&lt;br /&gt;
En general, las funcionalidades que no muestran warnings en el instalador no suelen presentar problemas de incompatibilidad con otros recursos. Estas son:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esto no garantiza que cualquier combinación de recursos funcione: dos códigos todavía pueden utilizar la misma RAM, el mismo espacio de VRAM o modificar la misma rutina del juego. Además, &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, por lo que también debes considerar las restricciones de esta última.&lt;br /&gt;
&lt;br /&gt;
=== Funcionalidades con restricciones de compatibilidad ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad opcional !! Posibles conflictos y qué hacer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; || Puede entrar en conflicto con &#039;&#039;&#039;LX5&#039;s Powerups&#039;&#039;&#039;, &#039;&#039;&#039;Player 8x8 tiles DMAer&#039;&#039;&#039;, &#039;&#039;&#039;Player 32x32&#039;&#039;&#039; y otros sistemas que reemplazan la carga de gráficos o paletas del jugador. &#039;&#039;&#039;Player Revolution&#039;&#039;&#039; sí es compatible. Si tu sistema de jugador necesita esas rutinas originales, deja esta opción deshabilitada; también tendrás que deshabilitar &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; || Depende de &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y hereda sus restricciones de compatibilidad, aunque no muestre un warning propio. Si otro recurso es incompatible con &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, no puedes evitar ese conflicto habilitando únicamente &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;: debes dejar ambas deshabilitadas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt; || No es compatible con recursos que modifican, reemplazan o eliminan la barra de estado original, como &#039;&#039;&#039;LX5&#039;s DKC Style Status Bar&#039;&#039;&#039;, &#039;&#039;&#039;Minimalistic Status Bar&#039;&#039;&#039; y &#039;&#039;&#039;Nuke Status Bar&#039;&#039;&#039;. Si utilizas uno de ellos, deja esta optimización deshabilitada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt; || Integra el parche de optimización de VRAM de Lunar Magic de Kevin: utiliza esta versión en lugar del parche original por separado. Su warning también indica que &#039;&#039;&#039;no debe desinstalarse después de instalarla&#039;&#039;&#039;, porque hacerlo puede romper el funcionamiento de la ROM. Si necesitas revertirla, restaura una copia de seguridad anterior a su instalación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas funcionalidades son opcionales: puedes dejar deshabilitada la que entra en conflicto y seguir utilizando los demás sistemas de Dynamic Xtreme, respetando sus dependencias. Deshabilitar una opción no deshace los cambios de otro parche ni elimina la restricción de desinstalación de &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Espacios de RAM utilizados ===&lt;br /&gt;
&lt;br /&gt;
Las direcciones principales se configuran en &amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt;, dentro de la carpeta de Dynamic Xtreme. En el repositorio, ese archivo corresponde a &amp;lt;code&amp;gt;DynamicXtremeLibrary/ASM/DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El espacio utilizado depende de las funcionalidades habilitadas y de si la ROM utiliza SA-1. Los siguientes rangos incluyen el primer y el último byte y están calculados con &#039;&#039;&#039;todas las funcionalidades que reservan RAM habilitadas&#039;&#039;&#039;, &amp;lt;code&amp;gt;!VRAMTransferSize = 64&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!CGRAMTransferSize = 64&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuración !! Bloque &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; !! Tamaño !! Bloque &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; !! Tamaño&lt;br /&gt;
|-&lt;br /&gt;
| LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2000–$7E2500&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7E2800–$7E3608&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB440–$7FB940&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7F9C80–$7FAA88&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C000–$40C47E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$047F&amp;lt;/code&amp;gt;: 1151 bytes || &amp;lt;code&amp;gt;$418AFF–$419907&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los dos bloques internos suman &#039;&#039;&#039;4874 bytes en LoROM&#039;&#039;&#039; y &#039;&#039;&#039;4744 bytes en SA-1&#039;&#039;&#039;. La diferencia se debe a los 130 bytes del sistema de dibujo que solo se reservan en LoROM. No se ocupa automáticamente el espacio que queda entre los bloques.&lt;br /&gt;
&lt;br /&gt;
Al deshabilitar una funcionalidad se eliminan sus reservas condicionales y cambian las direcciones posteriores. Aumentar &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; también aumenta el tamaño de sus tablas.&lt;br /&gt;
&lt;br /&gt;
==== Tablas utilizadas por los sprites ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; &#039;&#039;&#039;no son espacios disponibles para escribir variables propias&#039;&#039;&#039;: a partir de esas posiciones se ubican las tablas de sprites de &amp;lt;code&amp;gt;DynamicXSpritesTables.asm&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;MoreSpriteMiscs.asm&amp;lt;/code&amp;gt;. También debes reservarlas si utilizas esos recursos.&lt;br /&gt;
&lt;br /&gt;
Con la misma configuración de la tabla anterior, sus rangos son:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuración !! Tablas desde &amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; !! Tamaño !! Tablas desde &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; !! Tamaño&lt;br /&gt;
|-&lt;br /&gt;
| LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2501–$7E26EC&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7E3609–$7E3824&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB941–$7FBB2C&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7FAC82–$7FAE9D&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C47F–$40C6D8&amp;lt;/code&amp;gt; || 602 bytes || &amp;lt;code&amp;gt;$419908–$419BCD&amp;lt;/code&amp;gt; || 710 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Incluyendo estas tablas, el espacio descrito suma &#039;&#039;&#039;5906 bytes en LoROM&#039;&#039;&#039; y &#039;&#039;&#039;6056 bytes en SA-1&#039;&#039;&#039;. Las tablas se calculan para 12 sprites normales en LoROM y 22 en SA-1, además de los slots de cluster, extended y smoke correspondientes.&lt;br /&gt;
&lt;br /&gt;
Normalmente, &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; comienza justo después del segundo bloque interno. En LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; se coloca por separado mediante &amp;lt;code&amp;gt;!Variables3 = $7FAC82&amp;lt;/code&amp;gt;; por eso sus tablas no empiezan inmediatamente después de &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme también utiliza los espejos existentes del color fijo y de la paleta: &amp;lt;code&amp;gt;$7E0701&amp;lt;/code&amp;gt; (2 bytes) y &amp;lt;code&amp;gt;$7E0703&amp;lt;/code&amp;gt; (512 bytes) en LoROM. En SA-1 sus direcciones declaradas son &amp;lt;code&amp;gt;$406701&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$006703&amp;lt;/code&amp;gt;. No son reservas adicionales dentro de los bloques anteriores ni direcciones libres para tus códigos.&lt;br /&gt;
&lt;br /&gt;
==== Reubicar la RAM si hay un conflicto ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Advertencia:&#039;&#039;&#039; para reubicar estas variables debes saber qué dirección elegir y considerar el tamaño completo del espacio de memoria que utiliza el sistema. No basta con que una dirección esté libre: debe haber espacio suficiente y las rutinas deben poder acceder a él. Si no tienes conocimientos sobre esto, consulta con alguien que los tenga antes de modificar las direcciones.&lt;br /&gt;
&lt;br /&gt;
Si otro recurso utiliza alguno de estos espacios, puedes modificar &#039;&#039;&#039;&amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt;&#039;&#039;&#039; para hacer que Dynamic Xtreme utilice otras zonas disponibles de tu romhack.&lt;br /&gt;
&lt;br /&gt;
* Cambia &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; en la configuración correspondiente a tu ROM: LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, LoROM sin esa opción o SA-1.&lt;br /&gt;
* En LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, revisa también &amp;lt;code&amp;gt;!Variables3&amp;lt;/code&amp;gt;, que determina dónde empiezan las tablas de &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Reserva espacio suficiente para el bloque completo y las tablas de sprites que le siguen. No basta con que la primera dirección esté libre.&lt;br /&gt;
* Respeta el mapa de memoria y los bancos que necesitan las rutinas. No cualquier dirección libre sirve para cualquier acceso.&lt;br /&gt;
* Después de cambiar las direcciones, reinstala Dynamic Xtreme y vuelve a insertar PIXI, UberASM y los demás recursos que utilicen sus defines.&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, Dynamic Xtreme aprovecha el área de RAM que recupera al reubicar los gráficos originales; no la compartas con otros recursos sin comprobar qué parte utiliza. Sin esa opción, las direcciones alternativas pueden coincidir con las de otros recursos habituales. SA-1 utiliza sus propias direcciones y desactiva &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Modifica el archivo de la carpeta &#039;&#039;&#039;ASM&#039;&#039;&#039;, no las copias generadas en &amp;lt;code&amp;gt;ExtraDefines&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;Patch/ExtraDefines&amp;lt;/code&amp;gt;: esas copias se regeneran durante la instalación.&lt;br /&gt;
&lt;br /&gt;
== Recursos hechos con Dynamic Xtreme ==&lt;br /&gt;
&lt;br /&gt;
La mayoría de los recursos desarrollados para Dynamic Xtreme no suelen publicarse en sitios tradicionales como SMW Central debido a que muchos de ellos dependen directamente del framework y sus sistemas avanzados.&lt;br /&gt;
&lt;br /&gt;
En su lugar, los recursos, ejemplos, sistemas y proyectos relacionados con Dynamic Xtreme se encuentran recopilados principalmente en:&lt;br /&gt;
&lt;br /&gt;
https://snestorage.dev&lt;br /&gt;
&lt;br /&gt;
Allí es posible encontrar sprites, sistemas de jugador, efectos gráficos, ejemplos técnicos y otros recursos diseñados específicamente para trabajar con Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
== Conclusión ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es un proyecto orientado a modernizar y simplificar el uso de sistemas dinámicos en Super Mario World, ofreciendo herramientas más flexibles, potentes y fáciles de utilizar sin perder compatibilidad ni control avanzado.&lt;br /&gt;
&lt;br /&gt;
El proyecto continúa evolucionando constantemente con nuevas optimizaciones, formatos y herramientas orientadas tanto a usuarios avanzados como a personas que recién comienzan a trabajar con gráficos dinámicos en SNES.&lt;br /&gt;
&lt;br /&gt;
La intención principal de Dynamic Xtreme es permitir la creación de recursos y sistemas cada vez más complejos, manteniendo al mismo tiempo un workflow más limpio, mantenible y accesible para la comunidad.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_internal_workings&amp;diff=21400</id>
		<title>Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_internal_workings&amp;diff=21400"/>
		<updated>2026-10-25T22:13:18Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
This article explains how Dynamic Xtreme works, from preparing resources during installation to loading and drawing a pose during gameplay.&lt;br /&gt;
&lt;br /&gt;
== What installation prepares ==&lt;br /&gt;
&lt;br /&gt;
Before a sprite can use its graphics or palette, Dynamic Xtreme must store them in the ROM and prepare the information needed to find them. The same applies to any other dynamic resource you add.&lt;br /&gt;
&lt;br /&gt;
The tool reads DynamicInfo, DrawInfo, and PaletteEffect files. Each provides a different part: which resources to load, how to draw poses, and which color changes can be applied.&lt;br /&gt;
&lt;br /&gt;
This generates defines in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; that make it easy to use the resources and call the required routines.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: resources and upload data ===&lt;br /&gt;
&lt;br /&gt;
A DynamicInfo brings together the pose graphics, palettes, and general resources needed by a sprite or other code. For dynamic pose graphics, the tool arranges the data in the tile layout expected by the system.&lt;br /&gt;
&lt;br /&gt;
Several properties of each pose are stored in separate tables. All tables use the same order: a pose&#039;s entry in one table corresponds to the same pose in the others. In the table below, &#039;&#039;&#039;N&#039;&#039;&#039; is the number of installed dynamic poses.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Total bytes !! Bytes per value !! Contents and purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || 2 × N || 2 || Amount of data used by each pose, in bytes. Used to check whether its upload fits within the frame&#039;s budget.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || N || 1 || Number of 16×16 blocks to allocate in VRAM for the pose. This does not always match the exact byte count copied, since an incomplete tile can still require a block of space.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 × N || 3 || ROM address of each pose&#039;s graphics, including the bank, so upload code can locate the full source address.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 × N || 2; two values per pose || Two sizes per pose, corresponding to the two sections its graphics may be split into. The upload routine uses them to place the data correctly in VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 × N || 2 || VRAM offset from the start of the first section to the start of the second. Places the second section correctly even if the first ends with an incomplete row.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These tables describe every installed pose, not just those on screen. The cache separately tracks which poses are loaded and where they are stored.&lt;br /&gt;
&lt;br /&gt;
For example, when a requested pose is not yet in VRAM, the system checks how many bytes it needs to upload, finds space for its blocks, then uses its source address and section data to prepare the upload.&lt;br /&gt;
&lt;br /&gt;
==== Palette tables ====&lt;br /&gt;
&lt;br /&gt;
Palettes declared in DynamicInfo files are collected in &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. If &#039;&#039;&#039;P&#039;&#039;&#039; is the number of entries across the DynamicInfo palette lists:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; || 2 × P || 2 || ID of each palette.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; || 3 × P || 3 || ROM address of its colors.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
P counts list entries, not just unique palettes: a shared palette may appear in more than one DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
Both lists follow the DynamicInfo palette order. Each DynamicInfo&#039;s offset define identifies where its list starts. Selecting a version adds that index to the offset to find both the ID and address of the chosen colors.&lt;br /&gt;
&lt;br /&gt;
The ID identifies a palette so it can be shared; the address allows its colors to be loaded. Neither is the destination palette number: the same installed palette may be assigned to palette 9 or C, for example.&lt;br /&gt;
&lt;br /&gt;
==== General resources and defines ====&lt;br /&gt;
&lt;br /&gt;
Files declared in &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; are stored in ROM. Their address and byte count are available through defines generated in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. For example, &amp;lt;code&amp;gt;my_resource.bin&amp;lt;/code&amp;gt; generates:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt;: resource address in ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt;: resource byte count.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt;: resource ID.&lt;br /&gt;
&lt;br /&gt;
Names are normalized to PascalCase: spaces, hyphens, and underscores are removed, and each word starts with a capital letter.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: drawing data and routines ===&lt;br /&gt;
&lt;br /&gt;
The DrawInfo describes how a pose is built: its tiles, each tile&#039;s position and size, and how the pose changes when flipped.&lt;br /&gt;
&lt;br /&gt;
During installation, Dynamic Xtreme generates drawing routines optimized for the parameters used by the tiles. For example, it considers whether tiles need X and Y offsets, share a size or common properties, and require flipping.&lt;br /&gt;
&lt;br /&gt;
The resulting routine only handles options that the drawing needs. Several poses can share a routine when they need the same handling; this does not mean they also share graphics or IDs.&lt;br /&gt;
&lt;br /&gt;
These tables connect a pose to its drawing data. &#039;&#039;&#039;D&#039;&#039;&#039; is the number of drawing poses, and &#039;&#039;&#039;R&#039;&#039;&#039; is the number of generated routines:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Total bytes !! Bytes per value !! Contents and purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || 2 × D || 2 || Starting offset of the pose&#039;s data in its drawing routine&#039;s tables. Locates its tiles and offsets without scanning earlier poses.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || D || 1 || Number of tiles in the pose minus one. A four-tile pose stores 3; the routine uses this to loop through its tiles.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || D || 1 || Drawing routine used by each pose. Poses with compatible requirements can use the same routine ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || 3 × R || 3 per routine || Drawing routine addresses. The routine ID selects the code to run.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each routine also has the tables its poses need. Here, &#039;&#039;&#039;T&#039;&#039;&#039; is the number of entries in each of the routine&#039;s tables:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Data !! Total bytes !! Bytes per value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || T, if generated || 1 || Tile numbers making up the pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || T, if generated || 1 || Each tile&#039;s properties, such as flipping and priority relative to the layers.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || T per table, if generated || 1 || Each tile&#039;s position relative to the pose&#039;s origin.&lt;br /&gt;
|-&lt;br /&gt;
| Flip displacement tables || T per table, if generated || 1 || Positions used when flipping a pose that requires a different layout.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || T, if generated || 1 || Each tile&#039;s size: 8×8 or 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Not every routine needs all these tables. If a value is the same for all tiles or can be obtained from a shared value, the tool can generate a routine that uses it directly.&lt;br /&gt;
&lt;br /&gt;
This optimization happens during installation. For example, when all tiles share a size, the routine can use that common value instead of reading a separate size for each tile.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: effect data ===&lt;br /&gt;
&lt;br /&gt;
A PaletteEffect file contains a list of color changes. Installation assigns IDs to them and stores their data in &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
As with pose tables, each effect occupies the same position across the different lists. Effect IDs start at 1; ID 0 means no global effect. In the table, &#039;&#039;&#039;E&#039;&#039;&#039; is the number of installed effects; together, the tables occupy &#039;&#039;&#039;2 + 7 × E bytes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table section !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || 2 || 2 || Number of installed effects.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || E || 1 || Each effect&#039;s type, such as &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Selects the calculation to perform.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || E per table; 3 × E combined || 1 per table || Channel values used by the effect. For transitions, these three bytes store the target palette address instead.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || E per table; 3 × E combined || 1 per table || How much of the change to apply to each component. Range: 0–127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For a transition toward another palette, the tool also prepares that palette. It converts the colors to the RGB or HSL format needed by the transition and stores them in ROM. During gameplay, this target can be used without converting it again on every call.&lt;br /&gt;
&lt;br /&gt;
These transition palettes differ from normal palettes uploaded to CGRAM: they contain three components per color and are used to calculate effects.&lt;br /&gt;
&lt;br /&gt;
=== How code finds installed resources ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; provides the IDs, addresses, sizes, and offsets resources need. For example, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifies a pose, and &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifies a file&#039;s first effect.&lt;br /&gt;
&lt;br /&gt;
Names are normalized to PascalCase: separators such as spaces, hyphens, and underscores are removed, and each word starts with a capital letter. For example, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Installation also generates &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, which stores the addresses of the blocks containing inserted resources. Each address occupies 3 bytes, followed by a final &amp;lt;code&amp;gt;$FFFFFF&amp;lt;/code&amp;gt; value occupying another 3 bytes. For B blocks, the table occupies &amp;lt;code&amp;gt;3 × (B + 1)&amp;lt;/code&amp;gt; bytes. The tool uses this information to find the previous installation&#039;s data when reinstalling.&lt;br /&gt;
&lt;br /&gt;
Reinstallation may change IDs and addresses. Reinsert any sprites, blocks, and UberASM code that use the generated defines afterward.&lt;br /&gt;
&lt;br /&gt;
== Work performed each frame ==&lt;br /&gt;
&lt;br /&gt;
The main game logic runs the player, sprites, and other code for the current game mode. Code using Dynamic Xtreme requests poses and palettes, prepares local effects, and calls drawing routines. Accepted uploads are added to the transfer lists for NMI.&lt;br /&gt;
&lt;br /&gt;
Once that logic finishes, Dynamic Xtreme&#039;s game mode code performs the tasks enabled by the configuration: preparing VRAM updates for Kevin&#039;s optimization, maintaining palette state, and calculating pending global effects.&lt;br /&gt;
&lt;br /&gt;
During NMI, Dynamic Xtreme then performs these tasks in order, according to the enabled features:&lt;br /&gt;
&lt;br /&gt;
# Resets &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; to 0.&lt;br /&gt;
# Increments &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Increments &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; if the action is not frozen and the game is not paused.&lt;br /&gt;
# Performs graphics transfers to VRAM.&lt;br /&gt;
# Performs color transfers to CGRAM.&lt;br /&gt;
# Updates color 0,0 if the effect system has a pending result.&lt;br /&gt;
&lt;br /&gt;
The following sections therefore follow this order: &#039;&#039;&#039;main logic → tasks at the end of the game mode → NMI transfers&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Main logic ===&lt;br /&gt;
&lt;br /&gt;
Each resource decides what it needs. A sprite may change pose, an animation may request new graphics, or UberASM code may upload a palette or select an effect.&lt;br /&gt;
&lt;br /&gt;
If the requested pose is already loaded, Dynamic Xtreme updates its last-use time to protect it from replacement without uploading its graphics again. Otherwise, it checks the frame&#039;s data budget and finds available VRAM space before preparing the upload.&lt;br /&gt;
&lt;br /&gt;
Drawing is also prepared here: routines write the positions, tiles, and properties of the pieces to display into the OAM buffers.&lt;br /&gt;
&lt;br /&gt;
A request can fail, for example because its data would exceed the remaining budget. The requesting code must check the result and decide whether to keep the previous state or retry later. A rejected upload is not automatically saved for another frame.&lt;br /&gt;
&lt;br /&gt;
=== Game mode tasks ===&lt;br /&gt;
&lt;br /&gt;
This stage performs the following tasks, according to the enabled features.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Before game logic runs:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# If &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt; is enabled, the controller routine runs here instead of during NMI.&lt;br /&gt;
# Checks whether Dynamic Xtreme should run in the current game mode. If not, its variables are reset. This happens every frame spent in a disallowed mode.&lt;br /&gt;
&lt;br /&gt;
The normal game logic then runs, including sprites and code requesting uploads or palette changes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;After that logic finishes:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# If Kevin&#039;s VRAM optimization is enabled, Lunar Magic&#039;s update destinations are adjusted before the transfers take place.&lt;br /&gt;
# Palette update flags are cleared to 0, and protection timers greater than 0 are decremented. This is skipped while paused and in disallowed modes.&lt;br /&gt;
# Applies global effects to palettes that need an update and prepares their color transfers. This is also skipped if the previous check prevents further processing.&lt;br /&gt;
&lt;br /&gt;
VRAM and CGRAM transfers happen later, during NMI. This stage prepares what will be copied.&lt;br /&gt;
&lt;br /&gt;
=== Allowed game modes ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme uses two game mode checks:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;General system:&#039;&#039;&#039; &amp;lt;code&amp;gt;Routines_AllowedGameMode&amp;lt;/code&amp;gt;, exposed as &amp;lt;code&amp;gt;!AllowedGameMode&amp;lt;/code&amp;gt;. Determines whether the system is reset, its NMI runs, and palette tasks are performed. Palette assignment macros also use this check when processing an upload from a DynamicInfo.&lt;br /&gt;
* &#039;&#039;&#039;Sprite routines:&#039;&#039;&#039; &amp;lt;code&amp;gt;DXAllowedGameMode&amp;lt;/code&amp;gt; uses a separate table. &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; and its general macros use a table with the same values to decide whether to process a new request.&lt;br /&gt;
&lt;br /&gt;
Enabling the general system therefore does not mean every sprite function accepts new uploads in that mode. This table shows the current checks; IDs are hexadecimal:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Game mode !! SMW screen or stage !! General system !! DXAllowedGameMode / new Upload requests&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt; || Title screen spotlight opening. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || Title screen. || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || File select. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$09&amp;lt;/code&amp;gt; || File erase. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt; || One- or two-player selection. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; || Overworld loading. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0D&amp;lt;/code&amp;gt; || Overworld fade-in. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; || Overworld. || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt; || Level preparation. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$13&amp;lt;/code&amp;gt; || Level fade-in. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || In-level gameplay. || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$15&amp;lt;/code&amp;gt; || Fade-out to Game Over / Time Up. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; || Castle cutscene or credits. || No || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt; || Fade-out to Yoshi&#039;s House in the credits. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1D&amp;lt;/code&amp;gt; || Loading Yoshi&#039;s House in the credits. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt; || Yoshi&#039;s House fade-in during the credits. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1F&amp;lt;/code&amp;gt; || Yoshi&#039;s House in the credits. || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$24&amp;lt;/code&amp;gt; || Enemy roll fade-in. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt; || Credits enemy roll. || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$29&amp;lt;/code&amp;gt; || The End screen. || No || Yes&lt;br /&gt;
|-&lt;br /&gt;
| Other values from &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$2F&amp;lt;/code&amp;gt;. || — || No || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Stage names follow the [https://github.com/IsoFrieze/SMWDisX/blob/master/bank_00.asm SMW game modes documented in SMWDisX]; permissions come from Dynamic Xtreme&#039;s tables.&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Upload&amp;lt;/code&amp;gt; does not allow a new request, it checks whether the resource has a previous pose. If so, it updates that pose&#039;s last-use time and returns carry set; otherwise, it returns carry clear. It does not request another pose on this path.&lt;br /&gt;
&lt;br /&gt;
Modes &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$29&amp;lt;/code&amp;gt; show why the columns must be read separately: passing the sprite check does not enable the general system&#039;s NMI or prevent the game mode code from resetting its variables. The sprite column alone does not guarantee full operation in those modes.&lt;br /&gt;
&lt;br /&gt;
=== Transfers during NMI ===&lt;br /&gt;
&lt;br /&gt;
NMI is an interrupt the SNES can generate at the start of VBlank, after drawing the visible part of the screen. The game uses this interval to update graphics, colors, and other video data.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The CPU runs both the game logic and the NMI routine.&#039;&#039;&#039; During game logic, it moves sprites and prepares upload requests. At the start of VBlank, an NMI can temporarily interrupt that logic to handle video updates. When the NMI routine finishes, the CPU resumes the interrupted code.&lt;br /&gt;
&lt;br /&gt;
This is the usual sequence within a frame:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Stage !! What the CPU does !! What happens to graphics&lt;br /&gt;
|-&lt;br /&gt;
| Game logic&lt;br /&gt;
| Moves sprites, selects poses, calculates effects, and prepares drawing.&lt;br /&gt;
| Accepted requests are stored in the transfer lists.&lt;br /&gt;
|-&lt;br /&gt;
| VBlank, during NMI&lt;br /&gt;
| Runs the NMI routine and sets up DMA transfers.&lt;br /&gt;
| Graphics are copied to VRAM, colors to CGRAM, and OAM data to OAM memory.&lt;br /&gt;
|-&lt;br /&gt;
| After NMI&lt;br /&gt;
| Resumes the interrupted code.&lt;br /&gt;
| The updated data is used to draw the next image.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This table shows the usual sequence; during slowdown, SMW may run a shortened NMI, as explained in the &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; section.&lt;br /&gt;
&lt;br /&gt;
In allowed modes, Dynamic Xtreme performs these tasks in order, according to the enabled features:&lt;br /&gt;
&lt;br /&gt;
# Resets &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; to 0 to count requests from the next logic cycle. Transfers already prepared remain in their lists.&lt;br /&gt;
# Increments &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Checks &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt;. If both are 0, increments &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Performs pending VRAM transfers if &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; is enabled.&lt;br /&gt;
# Performs pending CGRAM transfers if &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; is enabled.&lt;br /&gt;
# If &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; is enabled, updates color 0,0 when a result is pending.&lt;br /&gt;
&lt;br /&gt;
The copies use DMA. NMI reads each request from the lists, sets the source address, byte count, and destination, then starts the transfer.&lt;br /&gt;
&lt;br /&gt;
VBlank time is limited, and SMW also needs it for its own screen updates. To limit data sent in one frame and prevent flickering, Dynamic Xtreme uses &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; to count requested bytes and &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; to set the limit. Before accepting a normal upload, it checks whether the additional bytes would exceed that limit.&lt;br /&gt;
&lt;br /&gt;
==== Transfer lists ====&lt;br /&gt;
&lt;br /&gt;
Each request stores the source address and bank, byte count, and VRAM or CGRAM destination.&lt;br /&gt;
&lt;br /&gt;
NMI processes the lists from the last entry to the first, then empties them. This does not erase the uploaded graphics or colors: they stay at their destinations until other code changes them.&lt;br /&gt;
&lt;br /&gt;
The VRAM list uses 0 when empty. The CGRAM list uses &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; because it stores the last entry&#039;s index rather than the entry count directly.&lt;br /&gt;
&lt;br /&gt;
Code writing to the same destination must coordinate its uploads. Request order does not replace deciding which resource may use each region.&lt;br /&gt;
&lt;br /&gt;
Resources are normally read from ROM. If a resource is in a RAM buffer, you must keep its contents unchanged until NMI performs the transfer. For example, a palette prepared in RAM must not be modified or its buffer reused before the copy. The list stores the address, not a copy of the data; Dynamic Xtreme does not protect the buffer from changes made by other code.&lt;br /&gt;
&lt;br /&gt;
==== Data budget ====&lt;br /&gt;
&lt;br /&gt;
Transfer macros such as &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt; check the requested byte count in &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;. If the new upload would exceed &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, it is rejected. Accepted uploads add their bytes to the counter.&lt;br /&gt;
&lt;br /&gt;
The default limit is &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, or 2048 bytes. It helps prevent flickering caused by sending too much data in a frame. It limits data volume, rather than measuring the exact time each transfer takes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; tracks the requested byte count. The check &amp;lt;code&amp;gt;CurrentDataSend + resource bytes &amp;amp;gt; MaxDataPerFrame&amp;lt;/code&amp;gt; rejects a normal upload that would exceed the budget, limiting the data transferred during VBlank.&lt;br /&gt;
&lt;br /&gt;
Dynamic pose requests return the same failure result for insufficient budget and insufficient usable VRAM space. The call does not identify which condition prevented the upload. Failure does not mean VBlank was overloaded either: when the budget causes a rejection, the upload is rejected specifically to prevent that overload.&lt;br /&gt;
&lt;br /&gt;
Variants such as &amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;%ForcedTransferToCGRAM()&amp;lt;/code&amp;gt; accept uploads without checking the limit. Their bytes still count toward &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, leaving less room for later normal uploads. They are used for priority uploads, such as the player&#039;s graphics; they do not prevent flickering if too much data is requested.&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme_ASM_API#PPU|PPU in the ASM API]] for the difference between byte budget and list capacity, transfer restrictions, and the checks your code must perform.&lt;br /&gt;
&lt;br /&gt;
==== The two timers ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_Timer: protecting requests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; advances when Dynamic Xtreme&#039;s NMI code runs. Besides measuring how long a pose has gone unused, it prevents a resource from repeating requests before its previous ones have been processed.&lt;br /&gt;
&lt;br /&gt;
A logic cycle does not always correspond to a full NMI execution. During slowdown, SMW may run a shortened NMI, allowing two logic cycles to occur without Dynamic Xtreme&#039;s transfer lists being processed between them.&lt;br /&gt;
&lt;br /&gt;
Without protection, a resource could add its uploads to those lists again. Duplicate requests would take more space and could cause flickering.&lt;br /&gt;
&lt;br /&gt;
To prevent this, sprite pose upload routines compare &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; with a two-byte value stored by the sprite, usually called &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt;. The sprite aliases use &amp;lt;code&amp;gt;!SafeFrameLowByte,x&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!SafeFrameHighByte,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The process is:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Compare the timers.&#039;&#039;&#039; If &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; equals &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;, that sprite has already processed its pose upload at this timer value. The routine skips a new request.&lt;br /&gt;
# &#039;&#039;&#039;Record the attempt before processing it.&#039;&#039;&#039; If the values differ, it copies &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt;, then checks whether it can reuse the pose or must request another.&lt;br /&gt;
# &#039;&#039;&#039;Check the result.&#039;&#039;&#039; A new pose request can succeed or fail. Even if it fails, the value saved in &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; is not undone.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; therefore records &#039;&#039;&#039;when the last attempt was processed&#039;&#039;&#039;, not when a pose was successfully loaded. If an upload fails, calling the routine again with the same &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; does not allow another attempt, even if the desired pose or available space has changed.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;, rejected requests and calls skipped by this protection use the same fallback:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; is not &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, they update that pose&#039;s last-use time to protect it from replacement and return carry set. The sprite can keep drawing the last available pose.&lt;br /&gt;
* If it is &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no fallback pose exists and they return carry clear.&lt;br /&gt;
&lt;br /&gt;
For example, this can happen during slowdown:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;DX_Timer = $0030&amp;lt;/code&amp;gt;. The sprite saves &amp;lt;code&amp;gt;$0030&amp;lt;/code&amp;gt; in its &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; and tries to obtain a new pose. No data budget remains, so the request fails; it keeps the previous pose if one exists.&lt;br /&gt;
# SMW runs another logic cycle without processing Dynamic Xtreme&#039;s NMI. The timer is still &amp;lt;code&amp;gt;$0030&amp;lt;/code&amp;gt;. The same sprite&#039;s next call detects the match and does not repeat the request.&lt;br /&gt;
# When Dynamic Xtreme&#039;s NMI runs, &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; advances to &amp;lt;code&amp;gt;$0031&amp;lt;/code&amp;gt;. On the next call, the timers no longer match and the sprite can retry. A rejected request does not retry itself: the sprite code must call the routine again.&lt;br /&gt;
&lt;br /&gt;
Sprite pose upload aliases enable this protection. In [[Dynamic_Xtreme_ASM_API#GeneralUpload|GeneralUpload]] and [[Dynamic_Xtreme_ASM_API#Upload_(general_macro)|Upload (general macro)]], &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; controls it; &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; separately controls fallback to the previous pose. [[Dynamic_Xtreme_ASM_API#TakeDynamicRequest|TakeDynamicRequest]] and [[Dynamic_Xtreme_ASM_API#PPU|PPU transfer macros]] do not perform this &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; check for you.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; continues advancing while paused whenever this part of NMI runs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_SyncTimer: synchronized animations&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The main purpose of &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; is to give sprites a shared animation clock. For example, sprites using the same poses can use it to select a pose every four frames.&lt;br /&gt;
&lt;br /&gt;
They then change together and request the same pose. The first request may need to upload it; later requests reuse it without scheduling another graphics upload. This saves DMA transfers and data per frame.&lt;br /&gt;
&lt;br /&gt;
With independent timers, sprites could use different poses from the same animation at once, requiring more uploads and VRAM space.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; stops while paused or while the action is frozen, so synchronized animations stop too.&lt;br /&gt;
&lt;br /&gt;
== Graphics uploads: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; stores a list of upload requests in RAM. During NMI, those requests are processed and their data is copied to VRAM.&lt;br /&gt;
&lt;br /&gt;
=== List variables ===&lt;br /&gt;
&lt;br /&gt;
Here, &#039;&#039;&#039;V&#039;&#039;&#039; is &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt;, which defaults to 64. Each of the four request tables allocates V bytes; with 2-byte entries, that allows 32 requests. Together with the counter, they occupy &amp;lt;code&amp;gt;1 + 4 × V&amp;lt;/code&amp;gt; bytes: 257 by default.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable or table !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Number of pending requests. 0 means the list is empty.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || V; 64 by default || 2 || Each request&#039;s source address, excluding the bank.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || V; 64 by default || 2 allocated; 1-byte bank || Source bank.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || V; 64 by default || 2 || Number of bytes to copy.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || V; 64 by default || 2 || VRAM destination address.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Tables use the same order: the first entry of each table belongs to the first request, the second to the second request, and so on. Each entry occupies 2 bytes, so offsets advance through &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt;, and so on.&lt;br /&gt;
&lt;br /&gt;
These names represent RAM addresses calculated in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Addresses can change with the configuration and enabled features.&lt;br /&gt;
&lt;br /&gt;
=== Adding a request ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; performs these steps:&lt;br /&gt;
&lt;br /&gt;
# Calculates the total byte count if the new upload is added to &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Compares it with &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;. If it exceeds the limit, returns carry clear without adding the request.&lt;br /&gt;
# Uses &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; to find the next entry and increments that counter.&lt;br /&gt;
# Stores the source, bank, byte count, and destination in the tables.&lt;br /&gt;
# Updates &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; with the upload&#039;s byte count and returns carry set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; stores the same information without checking the byte limit. &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; variants make it easier to get the source from a full address or resource defines.&lt;br /&gt;
&lt;br /&gt;
Adding a request does not copy graphics immediately: it prepares the information for NMI.&lt;br /&gt;
&lt;br /&gt;
=== Processing requests during NMI ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt; routine:&lt;br /&gt;
&lt;br /&gt;
# Reads &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;. If it is 0, returns because there are no requests.&lt;br /&gt;
# Calculates the last entry&#039;s offset: &amp;lt;code&amp;gt;(Length - 1) × 2&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reads its source, bank, and byte count into the DMA registers.&lt;br /&gt;
# Writes the VRAM destination to &amp;lt;code&amp;gt;$2116-$2117&amp;lt;/code&amp;gt; and starts the transfer through &amp;lt;code&amp;gt;$420B&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Moves back 2 bytes to process the previous request, repeating until the first is complete.&lt;br /&gt;
# Writes 0 to &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; to mark the list as empty.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The list runs from last to first.&#039;&#039;&#039; There is no need to clear every stored value afterward: with the length at 0, the next request reuses the first entry.&lt;br /&gt;
&lt;br /&gt;
=== Animations with a fixed destination ===&lt;br /&gt;
&lt;br /&gt;
Animation code must:&lt;br /&gt;
&lt;br /&gt;
# Select the image for the current animation step.&lt;br /&gt;
# Calculate its source address.&lt;br /&gt;
# Request a transfer to the animation&#039;s VRAM destination.&lt;br /&gt;
# Check carry. If the upload is rejected, keep the previous image and retry.&lt;br /&gt;
&lt;br /&gt;
The destination can stay the same. Only the image copied there changes; the transfer list does not decide when the animation advances.&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme_UberASM_guide#Creating_graphics_animations|Creating graphics animations in the UberASM guide]] for complete code.&lt;br /&gt;
&lt;br /&gt;
=== Loading a dynamic pose ===&lt;br /&gt;
&lt;br /&gt;
Pose loading uses the cache to avoid uploading graphics that are already available:&lt;br /&gt;
&lt;br /&gt;
# Looks for the ID in the hash table.&lt;br /&gt;
# If already registered, updates its last-use time without adding another upload.&lt;br /&gt;
# Otherwise, checks the byte count and finds suitable space in the VRAM map.&lt;br /&gt;
# Selects poses that can be replaced, considering their time since last use and the new pose&#039;s space requirements.&lt;br /&gt;
# Updates the cache tables and map.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; splits the pose&#039;s data into the required transfers.&lt;br /&gt;
# NMI performs those transfers.&lt;br /&gt;
&lt;br /&gt;
[[#Dynamic_sprites:_DynamicPoses|Dynamic sprites: DynamicPoses]] covers each step, including hash lookup, the map, replacement policy, and splitting uploads into rows.&lt;br /&gt;
&lt;br /&gt;
== Palette uploads and assignment: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
The system distinguishes two values:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Palette ID:&#039;&#039;&#039; identifies colors stored in ROM.&lt;br /&gt;
* &#039;&#039;&#039;Destination color:&#039;&#039;&#039; specifies the starting color in CGRAM for the uploaded colors. For example, &amp;lt;code&amp;gt;$91&amp;lt;/code&amp;gt; starts at color 1 of palette 9.&lt;br /&gt;
&lt;br /&gt;
Automatic assignment lets sprites share colors without requiring a fixed destination for each sprite.&lt;br /&gt;
&lt;br /&gt;
=== CGRAM upload list ===&lt;br /&gt;
&lt;br /&gt;
Here, &#039;&#039;&#039;C&#039;&#039;&#039; is &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt;, which defaults to 64. The tables and counter allocate &amp;lt;code&amp;gt;1 + 7 × C&amp;lt;/code&amp;gt; bytes, or 449 by default. Although &amp;lt;code&amp;gt;SourceBNK&amp;lt;/code&amp;gt; allocates 2 × C bytes, the code uses one bank byte per request.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable or table !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Last pending request&#039;s index. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; means the list is empty; 0 means one request.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || 2 × C; 128 by default || 2 || Source address, excluding the bank.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || 2 × C; 128 allocated by default || 1 used per request || Source bank.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || 2 × C; 128 by default || 2 || Number of bytes to copy. Each color occupies 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || C; 64 by default || 1 || First destination color in CGRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
During NMI, &amp;lt;code&amp;gt;CGRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Starts at the last pending request.&lt;br /&gt;
# Configures DMA with that request&#039;s source and byte count.&lt;br /&gt;
# Selects the first color through &amp;lt;code&amp;gt;$2121&amp;lt;/code&amp;gt; and performs the copy.&lt;br /&gt;
# Continues with earlier requests.&lt;br /&gt;
# Writes &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; when finished.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; macros also update the color copies and effect state:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Without the global effect:&#039;&#039;&#039; request the upload and update SMW&#039;s buffers, preventing the game from reusing old colors during the goal victory animation.&lt;br /&gt;
* &#039;&#039;&#039;With the global effect:&#039;&#039;&#039; store the original colors and prepare the state needed to apply the effect before sending them to CGRAM.&lt;br /&gt;
&lt;br /&gt;
=== Automatic assignment ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable or table !! Total bytes !! Bytes per value !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 32 || 2 || ID assigned to each destination. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; marks a free entry; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; marks one set aside.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 16 || 1 || Protects each destination from automatic replacement while in use.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 || 1; one bit per sprite palette || Tracks sprite palettes assigned with the global effect enabled. Sharing an assignment also requires this setting to match.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The search follows this order:&lt;br /&gt;
&lt;br /&gt;
# Reuse an assignment with the same ID and compatible effect setting.&lt;br /&gt;
# If none exists, use a free entry.&lt;br /&gt;
# If none is free, replace an entry that is not set aside and whose timer is 0.&lt;br /&gt;
# If no entry qualifies, report assignment failure.&lt;br /&gt;
&lt;br /&gt;
While using the palette, the resource keeps its timer at 2. Reaching 0 does not erase the colors: the assignment can still be reused if another resource has not replaced it.&lt;br /&gt;
&lt;br /&gt;
=== Manual assignment and version ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Manual with upload:&#039;&#039;&#039; code selects the destination and requests its colors.&lt;br /&gt;
* &#039;&#039;&#039;Manual without upload:&#039;&#039;&#039; code selects the destination and uses the colors already available there.&lt;br /&gt;
* &#039;&#039;&#039;Version:&#039;&#039;&#039; selects an entry in the DynamicInfo palette list. The last processed version lets the system check whether that selection changed.&lt;br /&gt;
&lt;br /&gt;
Resources choosing the same destination with different colors must coordinate their uploads. Keeping a palette protected does not mean uploading its colors again.&lt;br /&gt;
&lt;br /&gt;
== Pose drawing: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
Drawing prepares a pose&#039;s pieces in OAM: the tiles to display, their positions, and their properties. The graphics data must be in VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Drawing steps ===&lt;br /&gt;
&lt;br /&gt;
# Finds the pose&#039;s routine and data through &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Gets the tile count from &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Calculates each tile&#039;s position from the sprite position, displacements, and applicable flips.&lt;br /&gt;
# Checks whether the tile is visible and OAM space remains.&lt;br /&gt;
# Writes its position, tile number, properties, and size to the OAM buffers.&lt;br /&gt;
&lt;br /&gt;
The tile number depends on the drawing type:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Case !! How the tile is selected&lt;br /&gt;
|-&lt;br /&gt;
| Dynamic pose || Adjusted to the graphics&#039; location in VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| Static pose || Uses its fixed tile number.&lt;br /&gt;
|-&lt;br /&gt;
| Pose using a shared tile || Code must set &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; before drawing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Priority and available space ===&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;LoROM&#039;&#039;&#039;, the system tracks available OAM entries itself.&lt;br /&gt;
* In &#039;&#039;&#039;SA-1&#039;&#039;&#039;, it integrates with MaxTile.&lt;br /&gt;
* &#039;&#039;&#039;Drawing priority&#039;&#039;&#039; orders sprite tiles. It is separate from the property that places a tile in front of or behind layers.&lt;br /&gt;
* SNES &#039;&#039;&#039;per-scanline limits&#039;&#039;&#039; still apply. Loading a pose does not guarantee that all its tiles can be displayed.&lt;br /&gt;
&lt;br /&gt;
== Player and Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
The original player has its own routines to select and upload pose pieces. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; integrates that work with Dynamic Xtreme uploads and lets you change the graphics and palette sources.&lt;br /&gt;
&lt;br /&gt;
With the original format, the game still selects the pose pieces. The routine gets their addresses from the configured source and compares them with the previous addresses to upload only those that changed.&lt;br /&gt;
&lt;br /&gt;
These uploads use forced transfers, and their bytes also count toward later normal requests. They retain priority while remaining part of the system&#039;s data budget.&lt;br /&gt;
&lt;br /&gt;
The player&#039;s palette receives special handling: it combines the game&#039;s own colors and selections with the custom source. It is more involved than replacing an ordinary sprite&#039;s entire palette.&lt;br /&gt;
&lt;br /&gt;
Support for custom players lets other systems handle their poses and drawing differently. It does not automatically convert any spritesheet to the original player&#039;s format.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi also uploads graphics in pieces. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; lets you change their source while retaining the layout expected by the routines.&lt;br /&gt;
&lt;br /&gt;
The code calculates which pieces are needed and prepares uploads to the corresponding VRAM destinations. Like the player&#039;s uploads, these receive priority handling.&lt;br /&gt;
&lt;br /&gt;
This option requires &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; and shares its compatibility restrictions. Enabling Yoshi&#039;s features alone does not avoid a conflict with the player system.&lt;br /&gt;
&lt;br /&gt;
== Differences between LoROM and SA-1 ==&lt;br /&gt;
&lt;br /&gt;
The main differences in Dynamic Xtreme between these configurations are the memory used for its variables and the drawing system:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Aspect !! LoROM !! SA-1&lt;br /&gt;
|-&lt;br /&gt;
| Memory for variables&lt;br /&gt;
| &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; is commonly used to provide space for Dynamic Xtreme&#039;s variables in the recovered RAM. If this option causes compatibility problems, it can be disabled in favor of the alternative configuration, which uses a tighter RAM allocation.&lt;br /&gt;
| Does not use &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;. The main variable areas are in BW-RAM, in banks &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$41&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Drawing priorities&lt;br /&gt;
| Uses Dynamic Xtreme&#039;s own system, with two drawing priorities.&lt;br /&gt;
| Uses MaxTile, with four drawing priorities for tiles.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
LoROM&#039;s two priorities cannot preserve every ordering distinction available with SA-1&#039;s four priorities. Some resources that draw correctly on SA-1 may therefore appear in a different or incorrect drawing order on LoROM. These priorities order sprite tiles; they are separate from the priority that places tiles in front of or behind layers.&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme#RAM_usage|RAM usage]] for each configuration&#039;s memory ranges.&lt;br /&gt;
&lt;br /&gt;
== Memory and optimizations ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW keeps original player, Yoshi, and some animation graphics in RAM. In ROMs without SA-1, this option adapts uploads to read that data from ROM instead.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme uses the recovered RAM for its internal variables. It is not free space for other code to overwrite.&lt;br /&gt;
&lt;br /&gt;
SA-1 uses different addresses and disables this option. See the ranges in [[Dynamic_Xtreme#RAM_usage|RAM usage]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
This option moves controller processing from NMI to the game mode code. It frees time for screen updates without adding a frame of input delay or changing which buttons the game receives.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
The console uses the fixed color for color math. To update it, the game prepares its components and sends them to the corresponding register.&lt;br /&gt;
&lt;br /&gt;
This optimization replaces that preparation with a shorter sequence. The color is still sent to the console, with less work required during NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic uses lists called stripe images to update parts of the tilemaps. These contain both the data and destination information.&lt;br /&gt;
&lt;br /&gt;
The integrated version of Kevin&#039;s optimization prepares part of the destination adjustment outside NMI, leaving less setup work for transfer time.&lt;br /&gt;
&lt;br /&gt;
This option replaces the standalone original patch. It must not be uninstalled after installation; keep this in mind before enabling it.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
The original status bar updates specific VRAM regions. This option prepares its transfers more directly, reducing the DMA setup needed during NMI.&lt;br /&gt;
&lt;br /&gt;
It modifies updates to the original status bar rather than adding a new one. As a result, it conflicts with resources that replace, modify, or remove that bar.&lt;br /&gt;
&lt;br /&gt;
== Dynamic sprites: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
The system works as a &#039;&#039;&#039;pose cache in VRAM&#039;&#039;&#039;. Instead of keeping a graphics copy for each sprite, it stores a pose that every resource needing it can reuse.&lt;br /&gt;
&lt;br /&gt;
* A pose is uploaded only once while it remains in the cache.&lt;br /&gt;
* Later requests update its last-use time without adding another graphics upload.&lt;br /&gt;
* A pose is not erased when a resource stops using it. It stays until its space is needed and it is selected for replacement.&lt;br /&gt;
* If replaced and later requested again, it must be uploaded again.&lt;br /&gt;
&lt;br /&gt;
Replacement depends on &#039;&#039;&#039;time since last use&#039;&#039;&#039;, not time since upload, as well as whether the space fits the new pose.&lt;br /&gt;
&lt;br /&gt;
=== Three different values ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Value !! What it identifies&lt;br /&gt;
|-&lt;br /&gt;
| Pose ID || The installed pose. A 16-bit value used to look up its data in ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Hash table index || The RAM entry that records the pose. Ranges from 0 to 127.&lt;br /&gt;
|-&lt;br /&gt;
| VRAM block || ID of one of the 128 16×16 tile positions in sprite VRAM. Numbered left to right and top to bottom, from 0 to 127. A pose occupying several blocks stores its first block&#039;s ID.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The hash table index and VRAM block do not need to match. A table entry can record a pose starting at any allowed block.&lt;br /&gt;
&lt;br /&gt;
=== Registered pose tables ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable or table !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 || 1 || Number of registered poses.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 || 1 || Number of registered poses for each hash.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 256 || 2 || Full pose ID in each entry. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; marks a free entry.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Starting VRAM block of each pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 256 || 2 || &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; value at the pose&#039;s last use.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These tables occupy &#039;&#039;&#039;769 bytes&#039;&#039;&#039; of RAM. They track poses registered during gameplay, whereas the DynamicInfo-generated tables describe every installed pose.&lt;br /&gt;
&lt;br /&gt;
=== Looking up a pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicPoseHashmap_FindPose&amp;lt;/code&amp;gt; uses a 128-entry hash table. The hash selects where to start searching:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hash = pose ID AND $007F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Different IDs can share a hash. For example, &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; both produce &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;. The hash alone therefore cannot confirm that a pose is loaded; the full ID must also match.&lt;br /&gt;
&lt;br /&gt;
The search follows these steps:&lt;br /&gt;
&lt;br /&gt;
# Saves the requested ID and calculates its hash.&lt;br /&gt;
# If &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; is 0, no poses are registered and the search ends.&lt;br /&gt;
# Checks &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize[hash]&amp;lt;/code&amp;gt;. If it is 0, no registered pose has that hash, so the search also ends.&lt;br /&gt;
# Starts at the entry whose index matches the hash.&lt;br /&gt;
# Reads that entry&#039;s ID. If it matches the requested ID, the pose has been found.&lt;br /&gt;
# Otherwise, continues to the next entry in the search sequence.&lt;br /&gt;
&lt;br /&gt;
The sequence advances &#039;&#039;&#039;15 entries per attempt&#039;&#039;&#039;, wrapping around after 127:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
next index = (current index + 15) AND $7F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With 128 entries, this step visits every position before repeating one. For hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, the sequence starts:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$05 → $14 → $23 → $32 → $41 → ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The pose count for each hash ====&lt;br /&gt;
&lt;br /&gt;
Each hash has its own counter in &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt;. For example, if two registered poses have IDs that produce hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize+$05&amp;lt;/code&amp;gt; contains 2.&lt;br /&gt;
&lt;br /&gt;
This number tells the search &#039;&#039;&#039;how many poses have that hash&#039;&#039;&#039;, not how many positions to visit. The search uses a temporary copy of the counter:&lt;br /&gt;
&lt;br /&gt;
# Starts with the registered pose count for the requested hash.&lt;br /&gt;
# Visits positions in the sequence until it finds the requested ID or has checked that many poses with the same hash.&lt;br /&gt;
# Each time it finds a pose with the same hash but a different ID, decrements the temporary counter.&lt;br /&gt;
# Free positions and poses with other hashes do not decrement it; the search continues.&lt;br /&gt;
# If the temporary counter reaches 0 without finding the ID, the requested pose is not registered and the search ends.&lt;br /&gt;
&lt;br /&gt;
The counter in &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; does not change during lookup. It changes only when poses are added to or removed from the cache.&lt;br /&gt;
&lt;br /&gt;
For example, suppose the requested ID is &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt;, which produces hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, and that hash&#039;s counter is 2:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Visited position !! Stored ID !! ID&#039;s hash !! Hash $05 poses still to check&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 1: same hash, but a different ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0014&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || 1: different hash, so the counter is unchanged.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$23&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 0: both poses with this hash have been checked. &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt; is not registered.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Usually, each hash has one or two poses. This allows lookup with few comparisons and a typical cost close to &amp;lt;code&amp;gt;O(1)&amp;lt;/code&amp;gt;. It does not mean only one or two positions are always visited: entries with other hashes may lie between them. Many collisions can make the search longer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A free entry does not end the search.&#039;&#039;&#039; It may have been emptied by replacing a pose, with another pose of the same hash still farther along the sequence. The counter tells the search when all poses with that hash have been checked, even with gaps between them.&lt;br /&gt;
&lt;br /&gt;
==== When the pose is found ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Gets the matching entry&#039;s index.&lt;br /&gt;
# Writes the current &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; value to that entry&#039;s &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reports request success without scheduling another graphics upload.&lt;br /&gt;
&lt;br /&gt;
All resources requesting that ID therefore use the same pose and keep it protected. They may be normal, cluster, or extended sprites, or any other code using the system.&lt;br /&gt;
&lt;br /&gt;
This also prevents duplicate uploads within one cycle: once the first request is accepted, the pose is registered even though the actual transfer will occur during NMI.&lt;br /&gt;
&lt;br /&gt;
=== When the pose is not registered ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt; proceeds with a new upload:&lt;br /&gt;
&lt;br /&gt;
# Reads &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; and calculates &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend + PoseSize&amp;lt;/code&amp;gt;.&lt;br /&gt;
# If the result exceeds &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, returns failure without changing existing poses.&lt;br /&gt;
# Reads &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; to find the required block count.&lt;br /&gt;
# Calls &amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; to find suitable space.&lt;br /&gt;
# If no usable space exists, returns failure.&lt;br /&gt;
# Removes poses occupying the chosen space from the map and hash table.&lt;br /&gt;
# Finds a free hash table entry and registers the new pose.&lt;br /&gt;
# Updates the VRAM map and frame data counter.&lt;br /&gt;
# Calls &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; to add the transfers.&lt;br /&gt;
&lt;br /&gt;
The budget check happens before replacing poses. If the new upload cannot fit in the frame, no space is freed for a request that cannot be fulfilled.&lt;br /&gt;
&lt;br /&gt;
==== Adding and removing hash table entries ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_FindFreeSpace&amp;lt;/code&amp;gt; looks for an entry whose ID is &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt;, using the same sequence of 15-entry steps.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; stores the ID and last-use time, increments &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt;, and increments the corresponding hash counter.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Remove&amp;lt;/code&amp;gt; writes &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; to the removed ID and decrements both counters.&lt;br /&gt;
&lt;br /&gt;
Removing an entry does not itself erase VRAM pixels. It marks the pose as unavailable in the cache; the new transfers overwrite the chosen space.&lt;br /&gt;
&lt;br /&gt;
=== Representing the VRAM map ===&lt;br /&gt;
&lt;br /&gt;
The map represents &#039;&#039;&#039;128 16×16 tile positions in sprite VRAM&#039;&#039;&#039;, numbered left to right and top to bottom. Each block is one of those positions, not a contiguous 128-byte range.&lt;br /&gt;
&lt;br /&gt;
A 16×16 tile consists of four 8×8 tiles arranged in two rows. The map manages the positions occupied by a pose; &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; later handles how its data must be distributed for upload.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Section&#039;s starting position. Bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; marks it as restricted: dynamic poses cannot use this space.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt;, also called &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 || 1 || If bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; is set, the remaining bits hold the section&#039;s position count minus one. Otherwise, they hold the occupying pose&#039;s hash index. Check &amp;lt;code&amp;gt;Offset&amp;lt;/code&amp;gt; to determine whether the space is restricted.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These two tables occupy &#039;&#039;&#039;256 bytes&#039;&#039;&#039;. Together with the pose tables, the manager uses &#039;&#039;&#039;1025 bytes&#039;&#039;&#039; of RAM, excluding transfer lists and working scratch memory.&lt;br /&gt;
&lt;br /&gt;
=== Map sections ===&lt;br /&gt;
&lt;br /&gt;
A section groups consecutive map positions that are restricted, free, or occupied by one pose. Its information is stored at &#039;&#039;&#039;the first and last positions&#039;&#039;&#039;, allowing traversal to jump to the previous section without checking every position in between.&lt;br /&gt;
&lt;br /&gt;
The following examples show three possible states for a 6-position section from &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;. These are alternatives, not three sections occupying the same space at once.&lt;br /&gt;
&lt;br /&gt;
==== Example 1: restricted section ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table entries !! Value !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$A0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; marks the restriction; &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; identifies the start.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$85&amp;lt;/code&amp;gt; || The section has 6 positions: &amp;lt;code&amp;gt;($85 AND $7F) + 1 = 6&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Although the high bit of &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt; is set, &#039;&#039;&#039;this space is not free for dynamic poses&#039;&#039;&#039;: the restriction bit in &amp;lt;code&amp;gt;Offset&amp;lt;/code&amp;gt; excludes it. It is not evaluated as a replaceable pose.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; uses this section type to exclude parts of SP1–SP4 that dynamic sprites must not use.&lt;br /&gt;
&lt;br /&gt;
==== Example 2: free section ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table entries !! Value !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || Starts at &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; and is not restricted.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$85&amp;lt;/code&amp;gt; || Bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; marks a free section&#039;s size: &amp;lt;code&amp;gt;$05 + 1 = 6&amp;lt;/code&amp;gt; positions.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This section is available. It can hold a pose needing up to 6 positions; placing a 4-position pose leaves the other 2 as a separate free section.&lt;br /&gt;
&lt;br /&gt;
==== Example 3: section occupied by a pose ====&lt;br /&gt;
&lt;br /&gt;
Suppose a 6-block pose is registered at hash entry &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; and occupies positions &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table entries !! Value !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || The section starts at &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; and is not restricted.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || Bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; is clear: &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; is the pose&#039;s hash index, not its block count.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To find the position count and time since last use:&lt;br /&gt;
&lt;br /&gt;
# Read the pose ID at &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID+$0E&amp;lt;/code&amp;gt;. The offset is &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; because each ID occupies 2 bytes and &amp;lt;code&amp;gt;$07 × 2 = $0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Use that ID to read &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt;, which contains 6 in this example.&lt;br /&gt;
# Read &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse+$0E&amp;lt;/code&amp;gt; to calculate how long the pose has gone unused.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset+$07&amp;lt;/code&amp;gt; stores &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;, connecting the registered pose to its VRAM position.&lt;br /&gt;
&lt;br /&gt;
=== Traversal and space search ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; starts at 16×16 tile position &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt;. To traverse the map:&lt;br /&gt;
&lt;br /&gt;
# Reads &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; at the current position.&lt;br /&gt;
# Gets the section&#039;s start with &amp;lt;code&amp;gt;Offset AND $7F&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Evaluates that section and spaces it can form with adjacent sections.&lt;br /&gt;
# Moves to &amp;lt;code&amp;gt;section start - 1&amp;lt;/code&amp;gt;, the previous section&#039;s last position.&lt;br /&gt;
# Repeats until reaching the beginning of the map.&lt;br /&gt;
&lt;br /&gt;
For example, if the last sections start at &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Visited position !! Start read from Offset !! Next position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4F&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This traverses &#039;&#039;&#039;whole sections&#039;&#039;&#039;, not every tile in between.&lt;br /&gt;
&lt;br /&gt;
==== What the traversal evaluates ====&lt;br /&gt;
&lt;br /&gt;
A candidate space can consist of &#039;&#039;&#039;one section or several adjacent sections&#039;&#039;&#039;. At each step, the search checks:&lt;br /&gt;
&lt;br /&gt;
* A restricted section cannot be used, and sections cannot be combined across it.&lt;br /&gt;
* A pose protected by recent use cannot be part of the space either.&lt;br /&gt;
* If the candidate is still too small, an adjacent section can be added to reach the required block count.&lt;br /&gt;
* Once the pose fits, the candidate is compared with the best one found: first by its time-since-last-use score, then by the smallest sufficient space.&lt;br /&gt;
&lt;br /&gt;
A section is not chosen merely because it contains the longest-unused pose. The &#039;&#039;&#039;whole space&#039;&#039;&#039; must fit the new pose. When combining sections, the score depends on the most recently used pose within that space.&lt;br /&gt;
&lt;br /&gt;
The search keeps these temporary values:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Working data !! Total bytes !! Bytes per value !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapCurrentSpace&amp;lt;/code&amp;gt; || 3 || 1 per field || Start, score, and block count of the current candidate.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapBestSpace&amp;lt;/code&amp;gt; || 3 || 1 per field || Same fields for the best candidate found.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapTMP_Size&amp;lt;/code&amp;gt; || 1 || 1 || Block count needed by the new pose.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These names refer to working scratch memory, not additional persistent RAM.&lt;br /&gt;
&lt;br /&gt;
=== Replacement policy: time since last use and enough space ===&lt;br /&gt;
&lt;br /&gt;
The system does not simply choose the first pose uploaded. It uses the time since the pose&#039;s &#039;&#039;&#039;last use&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
time since last use = DX_Timer - pose TimeLastUse&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMapSlot_GetSizeAndScore&amp;lt;/code&amp;gt; gets each region&#039;s size and score:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Case !! Score and handling&lt;br /&gt;
|-&lt;br /&gt;
| Free region || &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Preferred over occupied regions.&lt;br /&gt;
|-&lt;br /&gt;
| Occupied region || Time since last use, capped at &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Unused for 0 or 1 timer increments || Cannot be replaced: the pose is still protected.&lt;br /&gt;
|-&lt;br /&gt;
| Restricted region || Excluded: dynamic poses cannot use this space.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Protection requires &#039;&#039;&#039;at least two increments of &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; without using the pose&#039;&#039;&#039; before it can be replaced. Each resource requesting it again updates its last-use time and protects it again.&lt;br /&gt;
&lt;br /&gt;
==== Why the longest-unused pose is not always replaced ====&lt;br /&gt;
&lt;br /&gt;
The new pose needs enough contiguous space. A small space alone is not useful, even if it has gone unused for a long time.&lt;br /&gt;
&lt;br /&gt;
For example, consider a new pose needing 4 blocks:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Candidate space !! Time since last use !! Suitable?&lt;br /&gt;
|-&lt;br /&gt;
| Pose A: 2 blocks, with no usable adjacent space || 20 || No: frees only 2 blocks.&lt;br /&gt;
|-&lt;br /&gt;
| Pose B: 4 blocks || 8 || Yes: fits the new pose.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Here, B can be replaced while A stays. A has gone unused longer, but its space cannot satisfy the request.&lt;br /&gt;
&lt;br /&gt;
If two or more adjacent regions can be replaced, the system can consider them together. It then:&lt;br /&gt;
&lt;br /&gt;
* Adds their block counts.&lt;br /&gt;
* Uses the &#039;&#039;&#039;lowest score&#039;&#039;&#039; among them: the shortest time since last use.&lt;br /&gt;
* Excludes any restricted or protected region from the combined space.&lt;br /&gt;
&lt;br /&gt;
This prevents a recently used pose from being overwritten just because it is next to a long-unused one.&lt;br /&gt;
&lt;br /&gt;
==== Choosing among valid candidates ====&lt;br /&gt;
&lt;br /&gt;
# The candidate must have at least the requested block count.&lt;br /&gt;
# The highest score wins: free space or the longest time since last use.&lt;br /&gt;
# If scores match, the smaller candidate wins, provided the pose fits.&lt;br /&gt;
# If score and size both match, the previously chosen candidate is kept.&lt;br /&gt;
&lt;br /&gt;
Regions are combined during the search when the candidate is still too small. The system does not combine every replaceable region regardless of the requested size.&lt;br /&gt;
&lt;br /&gt;
=== Replacing and splitting the chosen region ===&lt;br /&gt;
&lt;br /&gt;
Once the space is chosen:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemovePosesInSpace&amp;lt;/code&amp;gt; traverses its regions and removes poses being replaced from the hash table.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemoveSpace&amp;lt;/code&amp;gt; marks the chosen space as one free region by updating its endpoints.&lt;br /&gt;
# A free hash entry is found, and the starting block is stored in &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; registers the pose.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_AddPoseInSpace&amp;lt;/code&amp;gt; writes the pose&#039;s hash index and region start at the first and last blocks.&lt;br /&gt;
# Any leftover blocks become another free region.&lt;br /&gt;
&lt;br /&gt;
If a 6-block region holds a 4-block pose, it becomes a 4-block occupied region and a 2-block free region. Dynamic Xtreme has no VRAM defragmentation system: it does not move loaded poses to bring free spaces together.&lt;br /&gt;
&lt;br /&gt;
=== DynamicRoutine: preparing pose transfers ===&lt;br /&gt;
&lt;br /&gt;
At this point, space has been chosen and the pose registered. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; turns that allocation into transfer requests.&lt;br /&gt;
&lt;br /&gt;
It uses these values:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Data !! Amount read per pose !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Starting block || 1 byte || Position chosen by the VRAM map.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; || 2 bytes from a 256-byte table || Converts one of the 128 blocks to a VRAM offset.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 bytes || Full ROM address of the pose data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 bytes: two 2-byte values || Byte counts of the first and second sections.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 bytes || VRAM offset for the second section.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Converting the block to a VRAM address ====&lt;br /&gt;
&lt;br /&gt;
A 16×16 block does not convert to a simple linear byte offset. Each block uses 8×8 tiles distributed across VRAM rows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; accounts for that layout. For example:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Block !! Offset !! VRAM address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These VRAM addresses are measured in 2-byte words, not bytes. The routine adds the &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; base used for sprite graphics.&lt;br /&gt;
&lt;br /&gt;
==== Processing sections and rows ====&lt;br /&gt;
&lt;br /&gt;
# Gets the source from &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Processes the first section&#039;s bytes through &amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt;.&lt;br /&gt;
# If the second section&#039;s size is 0, returns.&lt;br /&gt;
# Otherwise, advances the source by the first section&#039;s byte count.&lt;br /&gt;
# Adds &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; to the VRAM offset and processes the second section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt; splits each section according to its rows and starting position. For destination V measured in VRAM words, it prepares:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
First row end = (V + $0100) AND $FF00&lt;br /&gt;
Bytes to that end = (first row end - V) × 2&lt;br /&gt;
Second part destination = first row end + $0100&lt;br /&gt;
Second part bytes in a group = $0200 - first part bytes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sizes are byte counts, while VRAM destinations are word addresses. This is why the calculation multiplies by 2 to find how many bytes fit before the end of a row.&lt;br /&gt;
&lt;br /&gt;
The routine uses three paths:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt;: adds one final request for the remaining bytes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLinesWithEndLine&amp;lt;/code&amp;gt;: adds two requests for the remaining data, each with its own destination and byte count.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLines&amp;lt;/code&amp;gt;: adds two requests totaling &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, advances the source and destinations, and repeats for the remaining data.&lt;br /&gt;
&lt;br /&gt;
A direct path precedes the general loop: if the destination starts on a &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt;-word boundary and the section contains at least &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, the routine uses &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt; to prepare the entire section as one request.&lt;br /&gt;
&lt;br /&gt;
For example, a &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt;-byte section starting at &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; is split as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Request !! Source !! VRAM destination !! Bytes&lt;br /&gt;
|-&lt;br /&gt;
| First || Section start || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt;: 448&lt;br /&gt;
|-&lt;br /&gt;
| Second || Section start + &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0040&amp;lt;/code&amp;gt;: 64&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Together, the two requests copy the section&#039;s 512 bytes to the destinations calculated from the row layout. They are not two complete copies of the pose.&lt;br /&gt;
&lt;br /&gt;
Each request uses these tables:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each added request increments &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The pose&#039;s total byte count was already checked and added to &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;. This stage splits that upload into transfers; it does not count the full pose again for each request.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; &#039;&#039;&#039;does not run DMA&#039;&#039;&#039;. It prepares requests for &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt; to process during NMI.&lt;br /&gt;
&lt;br /&gt;
=== What the sprite keeps ===&lt;br /&gt;
&lt;br /&gt;
Sprite routines store the usable pose&#039;s hash index, not a separate copy of its graphics. The index lets them look up its VRAM block and update its last-use time.&lt;br /&gt;
&lt;br /&gt;
If a new pose cannot be loaded:&lt;br /&gt;
&lt;br /&gt;
* A valid previous pose is kept, and its last-use time is updated to protect it.&lt;br /&gt;
* If no valid pose has ever been available, the code must not draw as though the request succeeded.&lt;br /&gt;
* Calls supporting fallback to the previous pose may return carry set because a pose is still usable, even though the change has not completed.&lt;br /&gt;
&lt;br /&gt;
Animation and movement remain the sprite&#039;s responsibility. The cache reuses or prepares the requested graphics.&lt;br /&gt;
&lt;br /&gt;
=== Example: two sprites request the same pose ===&lt;br /&gt;
&lt;br /&gt;
Suppose two visible sprites, A and B, need dynamic pose &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt;. Their palettes are ready, the pose is not yet in VRAM, and enough space and data budget remain.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Sprite A requests the pose.&#039;&#039;&#039; Lookup does not find &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; in the cache. The system chooses space, registers the pose, and prepares its graphics transfers. A stores the entry index in &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;. The graphics have not been copied to VRAM yet.&lt;br /&gt;
# &#039;&#039;&#039;A prepares its drawing.&#039;&#039;&#039; The drawing routine uses the registered entry to calculate tile numbers for that VRAM space and writes positions and properties to the OAM buffers.&lt;br /&gt;
# &#039;&#039;&#039;Sprite B requests the same pose.&#039;&#039;&#039; Lookup now finds &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; registered, even though its transfer is pending. It updates the last-use time without scheduling another upload. B stores the same cache index in its own &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &#039;&#039;&#039;B prepares its drawing.&#039;&#039;&#039; It writes its own tiles to the OAM buffers, using the same graphics as A with its own position, palette, and flip settings.&lt;br /&gt;
# &#039;&#039;&#039;NMI updates video data.&#039;&#039;&#039; The pending pose transfers copy the graphics to VRAM, and the game transfers the OAM buffers. Both sprites use the same uploaded graphics in the next displayed frame.&lt;br /&gt;
&lt;br /&gt;
Only one pose upload is prepared, even though two sprites use it. That upload may require several DMA transfers, depending on the graphics layout in VRAM.&lt;br /&gt;
&lt;br /&gt;
Here, a pose being &#039;&#039;&#039;available&#039;&#039;&#039; during logic means it has a registered entry, allocated space, and an upload prepared for NMI. If its graphics were already in VRAM, they are reused directly without preparing another transfer.&lt;br /&gt;
&lt;br /&gt;
If A&#039;s request were rejected, the new pose would not be registered and no upload would be pending. A would use its previous pose if available; otherwise, it would have no pose to draw. B would need to handle its own request and would not find an entry created by A&#039;s rejected attempt.&lt;br /&gt;
&lt;br /&gt;
== Palette effects: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
The system keeps the original colors so it can change effects, combine them, or restore the unaffected palette. An already affected result must not be treated as the original palette.&lt;br /&gt;
&lt;br /&gt;
=== Color buffers ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable or buffer !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 || 2 per color || Base colors in SNES format, with 2 bytes per color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 || 3 per color || Base colors split into red, green, and blue, with 3 bytes per color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 || 3 per color || Base colors split into hue, saturation, and lightness, with 3 bytes per color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 || 2 per color || SNES-format result, ready for a CGRAM transfer request. Corresponds to the game&#039;s palette buffer.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Per-palette flags ===&lt;br /&gt;
&lt;br /&gt;
Each bit in these flags corresponds to one palette. &amp;lt;code&amp;gt;BG&amp;lt;/code&amp;gt; variables cover 0–7; &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt; variables cover 8–F.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variables !! Total bytes !! Bytes per value !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseLoaded&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseLoaded&amp;lt;/code&amp;gt; || 1 per variable; 2 combined || 1; one bit per palette || Whether the SNES-format color base has been prepared.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 per variable; 2 combined || 1; one bit per palette || Whether the base has been converted to RGB.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 per variable; 2 combined || 1; one bit per palette || Whether the base has been converted to HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 per variable; 2 combined || 1; one bit per palette || Whether the global effect result is ready.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These flags avoid repeating conversions and calculations whose results remain valid.&lt;br /&gt;
&lt;br /&gt;
=== Preparing a base ===&lt;br /&gt;
&lt;br /&gt;
# Checks whether the palette already has a registered base.&lt;br /&gt;
# If not, gets the colors from the game&#039;s buffer. An explicit upload, such as &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, can supply that base directly.&lt;br /&gt;
# Checks whether the effect needs RGB or HSL.&lt;br /&gt;
# If that conversion is missing, prepares it and marks it as available.&lt;br /&gt;
&lt;br /&gt;
If only the effect changes, the base may remain valid. If the original colors change, upload calls update the base and invalidate conversions and results that must be recalculated.&lt;br /&gt;
&lt;br /&gt;
=== Effect data ===&lt;br /&gt;
&lt;br /&gt;
The ID selects data from the tables generated during installation:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt;: calculation to perform.&lt;br /&gt;
* &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt;: channel values, or a transition&#039;s target palette address.&lt;br /&gt;
* &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt;: how much of each change to apply.&lt;br /&gt;
&lt;br /&gt;
Channels range from 0 to 31. Ratios range from 0 to 127: 0 keeps the source unchanged, and 127 fully applies the selected change.&lt;br /&gt;
&lt;br /&gt;
Calculations run outside NMI. NMI transfers the resulting colors.&lt;br /&gt;
&lt;br /&gt;
=== Global effect ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Total bytes !! Bytes per value !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 || 2 || Selects the global effect. 0 restores the base colors.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 || 1; one bit per palette || Selects palettes 0–7 to receive the effect.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 || 1; one bit per palette || Selects palettes 8–F to receive the effect.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 32 || 2 || Last global effect ID processed for each palette.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 || 1 || Controls whether the fixed color and color 0,0 are affected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For each enabled palette, the manager:&lt;br /&gt;
&lt;br /&gt;
# Checks whether the effect result needs an update.&lt;br /&gt;
# Prepares the RGB or HSL base if missing.&lt;br /&gt;
# Calculates the effect if the previous result is no longer valid.&lt;br /&gt;
# Prepares SNES-format colors and requests their transfer.&lt;br /&gt;
# Records the processed ID when the corresponding upload is accepted.&lt;br /&gt;
&lt;br /&gt;
If the effect and base remain unchanged, recalculation is unnecessary. Changing the global ID invalidates previous results, but not necessarily the RGB and HSL bases.&lt;br /&gt;
&lt;br /&gt;
Global ID 0 also requires an update: the system must upload the base colors again to remove the previous effect.&lt;br /&gt;
&lt;br /&gt;
=== Local effects and concatenation ===&lt;br /&gt;
&lt;br /&gt;
A resource can have its own effect and also receive the global effect. For example, a sprite can change hue and then darken along with the level.&lt;br /&gt;
&lt;br /&gt;
The order is:&lt;br /&gt;
&lt;br /&gt;
# Prepare the local effect result.&lt;br /&gt;
# Use it as the global effect&#039;s base through the concatenation call.&lt;br /&gt;
# Calculate the global effect on that base.&lt;br /&gt;
# Upload the combined result without first displaying the local-only version.&lt;br /&gt;
&lt;br /&gt;
* Use RGB concatenation for RGB effects.&lt;br /&gt;
* Use HSL concatenation for HSL effects.&lt;br /&gt;
* Resources sharing a CGRAM destination share its colors. To display two different local effects, they need destinations that can keep both results separately.&lt;br /&gt;
&lt;br /&gt;
=== If the transfer is rejected ===&lt;br /&gt;
&lt;br /&gt;
* Calculating an effect does not mean it is already in CGRAM.&lt;br /&gt;
* If the transfer is rejected, the manager can retry the update.&lt;br /&gt;
* Where supported, the previous usable result is kept until it can be replaced.&lt;br /&gt;
* Do not upload the unaffected original colors first: they could appear for one frame before the correct result.&lt;br /&gt;
&lt;br /&gt;
== How the systems work together ==&lt;br /&gt;
&lt;br /&gt;
A dynamic sprite brings these tasks together:&lt;br /&gt;
&lt;br /&gt;
# Its logic selects the pose and palette version.&lt;br /&gt;
# Palette assignment finds a usable palette and prepares colors if needed.&lt;br /&gt;
# The cache protects the loaded pose or prepares a new upload.&lt;br /&gt;
# Drawing writes the pose&#039;s tiles to the OAM buffers.&lt;br /&gt;
# The effect manager prepares pending global changes.&lt;br /&gt;
# NMI performs the requested graphics and color transfers.&lt;br /&gt;
&lt;br /&gt;
Sharing graphics, sharing a palette, and sharing a drawing routine are three different things. Dynamic Xtreme can take advantage of each without requiring resources to share the others.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21399</id>
		<title>es/Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21399"/>
		<updated>2026-10-25T22:12:50Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo funciona Dynamic Xtreme, desde la preparación de los recursos al instalarlo hasta la carga y el dibujo de una pose durante el juego.&lt;br /&gt;
&lt;br /&gt;
== Qué prepara la instalación ==&lt;br /&gt;
&lt;br /&gt;
Antes de que un sprite pueda usar sus gráficos o una paleta, Dynamic Xtreme tiene que guardarlos en la ROM y preparar la información para encontrarlos. Lo mismo ocurre con cualquier otro recurso dinámico que hayas añadido.&lt;br /&gt;
&lt;br /&gt;
Para hacerlo, la herramienta lee los DynamicInfo, DrawInfo y PaletteEffect. Cada archivo aporta una parte distinta: qué recursos se van a cargar, cómo se dibujan las poses y qué cambios de color se pueden aplicar.&lt;br /&gt;
&lt;br /&gt;
Gracias a esta preparación se generan defines en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permiten utilizar los recursos y ejecutar fácilmente las rutinas necesarias.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: recursos y datos de carga ===&lt;br /&gt;
&lt;br /&gt;
Un DynamicInfo reúne los gráficos de poses, las paletas y los recursos generales que necesita un sprite u otro código. Si incluye gráficos de poses dinámicas, la herramienta los organiza para que puedan cargarse con la distribución de tiles que espera el sistema.&lt;br /&gt;
&lt;br /&gt;
Por cada pose guarda varios datos en tablas separadas. Todas mantienen el mismo orden: la entrada de una pose en una tabla corresponde a esa misma pose en las demás. En la tabla siguiente, &#039;&#039;&#039;N&#039;&#039;&#039; es la cantidad de poses dinámicas instaladas.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || 2 × N || 2 || La cantidad de datos que utiliza cada pose, en bytes. Se utiliza para comprobar si su carga cabe en el presupuesto del frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || N || 1 || Cuántos bloques de 16×16 hay que reservar en VRAM para la pose. No siempre coincide exactamente con los bytes que se copian, porque una pieza incompleta también puede necesitar un bloque de espacio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 × N || 3 || La dirección de los gráficos de cada pose en ROM. Incluye el banco, de modo que el código de carga pueda encontrar su origen completo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 × N || 2; dos valores por pose || Dos tamaños por pose, correspondientes a los dos tramos en que pueden dividirse sus gráficos. La rutina de carga utiliza esos tamaños para repartirlos correctamente en VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 × N || 2 || El desplazamiento en VRAM desde el comienzo del primer tramo hasta el comienzo del segundo. Permite colocar el segundo tramo donde corresponde, aunque el primero termine con una fila incompleta.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas describen todas las poses instaladas, no solo las que están en pantalla. Más adelante, la caché guarda por separado cuáles están cargadas y dónde quedaron.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si se solicita una pose que todavía no está en VRAM, el sistema consulta cuántos bytes necesita cargar, busca espacio para sus bloques y utiliza la dirección y los datos de sus tramos para preparar la carga.&lt;br /&gt;
&lt;br /&gt;
==== Tablas de paletas ====&lt;br /&gt;
&lt;br /&gt;
Las paletas declaradas en los DynamicInfo se reúnen en &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. Si &#039;&#039;&#039;P&#039;&#039;&#039; es la cantidad de entradas de las listas de paletas de los DynamicInfo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; || 2 × P || 2 || ID de cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; || 3 × P || 3 || Dirección de sus colores en ROM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
P cuenta las entradas de las listas, no solo las paletas distintas: una paleta compartida puede aparecer en más de un DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
Las dos listas siguen el orden de las paletas de los DynamicInfo. El define de offset de cada DynamicInfo indica dónde comienza su lista dentro de ellas. Al elegir una versión, el sistema suma ese índice al offset y obtiene tanto el ID como la dirección de los colores elegidos.&lt;br /&gt;
&lt;br /&gt;
El ID permite reconocer y compartir una paleta; la dirección permite cargarla. No son el número de paleta de pantalla: una misma paleta instalada puede terminar, por ejemplo, en la paleta 9 o en la C según la asignación.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y defines ====&lt;br /&gt;
&lt;br /&gt;
Los archivos declarados en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; se guardan en ROM. Su dirección y la cantidad de bytes que ocupan pueden consultarse mediante los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Por ejemplo, para &amp;lt;code&amp;gt;my_resource.bin&amp;lt;/code&amp;gt; se generan:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt;: dirección del recurso en ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt;: cantidad de bytes que ocupa.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt;: ID del recurso.&lt;br /&gt;
&lt;br /&gt;
El nombre se normaliza en PascalCase: se eliminan espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: datos y rutinas de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El DrawInfo describe cómo está formada una pose: qué tiles tiene, dónde se coloca cada uno, qué tamaño utiliza y cómo cambia al voltearse.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, Dynamic Xtreme genera rutinas de dibujo optimizadas según los parámetros que utilizan los tiles. Tiene en cuenta, por ejemplo, si necesitan desplazamientos X e Y, si comparten el mismo tamaño, si utilizan propiedades comunes y si requieren volteos.&lt;br /&gt;
&lt;br /&gt;
De esta forma, la rutina realiza el trabajo que necesita ese dibujo sin añadir el manejo de opciones que no utiliza. Varias poses pueden compartirla si necesitan el mismo tratamiento; eso no significa que compartan también sus gráficos o su ID.&lt;br /&gt;
&lt;br /&gt;
La relación entre una pose y su dibujo se guarda en estas tablas. &#039;&#039;&#039;D&#039;&#039;&#039; es la cantidad de poses de dibujo y &#039;&#039;&#039;R&#039;&#039;&#039; la cantidad de rutinas generadas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || 2 × D || 2 || Dónde comienzan los datos de la pose dentro de las tablas de su rutina de dibujo. Así se localizan sus tiles y desplazamientos sin recorrer las poses anteriores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || D || 1 || La cantidad de tiles de la pose menos uno. Una pose de cuatro tiles guarda 3; la rutina utiliza ese valor para recorrer sus piezas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || D || 1 || Qué rutina de dibujo utiliza cada pose. Las poses con características compatibles pueden apuntar al mismo ID de rutina.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || 3 × R || 3 por rutina || Las direcciones de las rutinas de dibujo. El ID de rutina permite encontrar aquí el código que debe ejecutarse.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada rutina tiene, además, las tablas que necesitan sus poses. Aquí &#039;&#039;&#039;T&#039;&#039;&#039; es la cantidad de entradas de cada tabla de la rutina:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos !! Bytes totales !! Bytes por valor !! Qué describen&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || T, si se genera || 1 || Los números de tile que forman la pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || T, si se genera || 1 || Las propiedades de cada pieza, como los volteos y su prioridad respecto a las capas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || T por tabla, si se genera || 1 || La posición de cada tile respecto al punto de origen de la pose.&lt;br /&gt;
|-&lt;br /&gt;
| Tablas de desplazamientos para los volteos || T por tabla, si se genera || 1 || Las posiciones que deben utilizarse al voltear la pose cuando necesita una distribución distinta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || T, si se genera || 1 || El tamaño de cada tile: 8×8 o 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
No todas estas tablas tienen que aparecer en todas las rutinas. Si un dato es igual para todas las piezas o puede obtenerse de un valor común, la herramienta puede generar una rutina que lo utilice directamente.&lt;br /&gt;
&lt;br /&gt;
La optimización se hace durante la instalación. Si todos los tiles tienen el mismo tamaño, por ejemplo, la rutina puede utilizar ese valor común sin leer un tamaño distinto para cada pieza.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: datos de los efectos ===&lt;br /&gt;
&lt;br /&gt;
Un archivo PaletteEffect contiene una lista de cambios de color. La instalación les asigna IDs y guarda sus datos en &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Como en las tablas de poses, los datos de cada efecto mantienen la misma posición en las distintas listas. Los IDs de efectos comienzan en 1; el ID 0 se utiliza para indicar que no hay efecto global. En la tabla, &#039;&#039;&#039;E&#039;&#039;&#039; es la cantidad de efectos instalados; el conjunto ocupa &#039;&#039;&#039;2 + 7 × E bytes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parte de la tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || 2 || 2 || La cantidad de efectos instalados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || E || 1 || El tipo de cada efecto, por ejemplo &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Indica qué cálculo debe realizarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || E por tabla; 3 × E entre las tres || 1 por tabla || Los valores de los canales que utiliza el efecto. En una transición, estos tres bytes guardan la dirección de la paleta de destino, no valores de canales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || E por tabla; 3 × E entre las tres || 1 por tabla || Cuánto se aplica el cambio en cada componente. Van de 0 a 127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Si el efecto es una transición hacia otra paleta, la herramienta también prepara esa paleta. Convierte sus colores al formato RGB o HSL que necesita la transición y los guarda en ROM. Durante el juego se puede utilizar ese destino sin tener que convertirlo de nuevo en cada llamada.&lt;br /&gt;
&lt;br /&gt;
Estas paletas de transición son distintas de las paletas normales que se cargan a CGRAM: contienen tres componentes por color y se utilizan para calcular el efecto.&lt;br /&gt;
&lt;br /&gt;
=== Cómo encuentra el código los recursos instalados ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; publica los IDs, direcciones, tamaños y offsets que necesitan los recursos. Por ejemplo, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifica una pose y &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifica el primer efecto de un archivo.&lt;br /&gt;
&lt;br /&gt;
Los nombres se normalizan en PascalCase: se eliminan separadores como espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra. &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, por ejemplo, pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También se genera &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, que guarda las direcciones de los bloques donde se insertaron los recursos. Cada dirección ocupa 3 bytes y se añade un valor final &amp;lt;code&amp;gt;$FFFFFF&amp;lt;/code&amp;gt; de otros 3 bytes. Para B bloques, ocupa &amp;lt;code&amp;gt;3 × (B + 1)&amp;lt;/code&amp;gt; bytes. La herramienta utiliza esa información para localizar los datos de una instalación anterior al reinstalar.&lt;br /&gt;
&lt;br /&gt;
Una reinstalación puede cambiar IDs y direcciones. Por eso hay que volver a insertar los sprites, bloques y códigos UberASM que utilizan los defines generados.&lt;br /&gt;
&lt;br /&gt;
== El trabajo de cada frame ==&lt;br /&gt;
&lt;br /&gt;
En la lógica principal se ejecutan el jugador, los sprites y los demás códigos del modo de juego. Los que utilizan Dynamic Xtreme solicitan las poses y paletas que necesitan, preparan los efectos locales y llaman a las rutinas de dibujo. Las cargas que se aceptan quedan anotadas para transferir sus datos durante NMI.&lt;br /&gt;
&lt;br /&gt;
Al terminar esa lógica, el código de game mode de Dynamic Xtreme realiza las tareas que correspondan a las opciones habilitadas: prepara las actualizaciones de VRAM de la optimización de Kevin, mantiene el estado de las paletas y calcula los efectos globales pendientes.&lt;br /&gt;
&lt;br /&gt;
Después, durante NMI, Dynamic Xtreme realiza estas tareas en orden, según las funcionalidades habilitadas:&lt;br /&gt;
&lt;br /&gt;
# Pone &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; en 0.&lt;br /&gt;
# Incrementa &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Incrementa &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; si la acción no está congelada ni el juego está en pausa.&lt;br /&gt;
# Ejecuta las transferencias de gráficos a VRAM.&lt;br /&gt;
# Ejecuta las transferencias de colores a CGRAM.&lt;br /&gt;
# Actualiza el color 0,0 si el sistema de efectos tiene un resultado pendiente.&lt;br /&gt;
&lt;br /&gt;
El orden que seguiremos para explicarlo es, por tanto, &#039;&#039;&#039;lógica principal → tareas al terminar el game mode → transferencias durante NMI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Lógica principal ===&lt;br /&gt;
&lt;br /&gt;
Cada recurso decide qué necesita. Un sprite puede cambiar de pose, una animación puede pedir nuevos gráficos y un código UberASM puede cargar una paleta o seleccionar un efecto.&lt;br /&gt;
&lt;br /&gt;
Si la pose solicitada ya está cargada, Dynamic Xtreme actualiza su tiempo de último uso para protegerla del reemplazo y no vuelve a cargar sus gráficos. Si no está cargada, comprueba el presupuesto de datos del frame y busca espacio disponible en VRAM antes de preparar su carga.&lt;br /&gt;
&lt;br /&gt;
El dibujo también se prepara en esta parte: las rutinas escriben en los buffers OAM la posición, los tiles y las propiedades de las piezas que se mostrarán.&lt;br /&gt;
&lt;br /&gt;
Una solicitud puede rechazarse, por ejemplo si no queda presupuesto para sus datos. El recurso que la pidió debe comprobar el resultado y decidir si conserva lo anterior o vuelve a intentarlo después. Una carga rechazada no queda guardada automáticamente para otro frame.&lt;br /&gt;
&lt;br /&gt;
=== Tareas de game mode ===&lt;br /&gt;
&lt;br /&gt;
En esta parte se realizan las siguientes tareas, según las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antes de ejecutar la lógica del juego:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitado &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;, se ejecuta la rutina del control aquí en lugar de hacerlo en NMI.&lt;br /&gt;
# Se comprueba si Dynamic Xtreme debe funcionar en el game mode actual. Si no debe hacerlo, se reinician sus variables. Esto ocurre cada frame que se permanezca en un modo no permitido.&lt;br /&gt;
&lt;br /&gt;
Después se ejecuta la lógica normal del juego, incluidos los sprites y los códigos que solicitan cargas o cambios de paleta.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cuando termina esa lógica:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitada la optimización de VRAM de Kevin, se ajustan los destinos de las actualizaciones de Lunar Magic antes de que se transfieran.&lt;br /&gt;
# Se ponen en 0 los indicadores de actualización de las paletas y se resta 1 a sus temporizadores de protección si todavía son mayores que 0. Esta parte se omite durante la pausa y en los modos no permitidos.&lt;br /&gt;
# Se aplican los efectos globales a las paletas que necesitan actualizarse y se preparan las transferencias de sus colores. Esta parte también se omite si la comprobación anterior impide continuar.&lt;br /&gt;
&lt;br /&gt;
Las copias a VRAM y CGRAM se realizan después, durante NMI. Aquí se deja preparado lo que se va a copiar.&lt;br /&gt;
&lt;br /&gt;
=== Game modes permitidos ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme utiliza dos comprobaciones de game mode:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Sistema general:&#039;&#039;&#039; &amp;lt;code&amp;gt;Routines_AllowedGameMode&amp;lt;/code&amp;gt;, publicado como &amp;lt;code&amp;gt;!AllowedGameMode&amp;lt;/code&amp;gt;. Se utiliza para decidir si se reinicializa el sistema, si se procesa su NMI y si se realizan las tareas de paletas. Las macros de asignación de paletas también consultan esta comprobación cuando necesitan procesar una carga del DynamicInfo.&lt;br /&gt;
* &#039;&#039;&#039;Rutinas de sprites:&#039;&#039;&#039; &amp;lt;code&amp;gt;DXAllowedGameMode&amp;lt;/code&amp;gt; utiliza una tabla distinta. La carga de poses mediante &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; y sus macros generales tiene una tabla con los mismos valores para decidir si procesa una solicitud nueva.&lt;br /&gt;
&lt;br /&gt;
Por tanto, que el sistema general esté habilitado no significa que todas las funciones de sprites acepten cargas nuevas en ese modo. Esta tabla muestra las comprobaciones actuales; los IDs están en hexadecimal:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Game mode !! Pantalla o etapa de SMW !! Sistema general !! DXAllowedGameMode / solicitudes nuevas de Upload&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt; || Apertura del foco de la pantalla de título. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || Pantalla de título. || Sí || Sí&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || Selección de partida. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$09&amp;lt;/code&amp;gt; || Borrado de partida. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt; || Selección de uno o dos jugadores. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; || Carga del overworld. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0D&amp;lt;/code&amp;gt; || Aparición gradual del overworld. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; || Overworld. || Sí || Sí&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt; || Preparación del nivel. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$13&amp;lt;/code&amp;gt; || Aparición gradual del nivel. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || Juego dentro del nivel. || Sí || Sí&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$15&amp;lt;/code&amp;gt; || Desvanecimiento hacia Game Over / Time Up. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; || Escena de castillo o créditos. || No || Sí&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt; || Desvanecimiento hacia la casa de Yoshi de los créditos. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1D&amp;lt;/code&amp;gt; || Carga de la casa de Yoshi de los créditos. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt; || Aparición gradual de la casa de Yoshi de los créditos. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1F&amp;lt;/code&amp;gt; || Casa de Yoshi de los créditos. || Sí || Sí&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$24&amp;lt;/code&amp;gt; || Aparición gradual de la presentación de enemigos. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt; || Presentación de enemigos de los créditos. || Sí || Sí&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$29&amp;lt;/code&amp;gt; || Pantalla «The End». || No || Sí&lt;br /&gt;
|-&lt;br /&gt;
| Los demás valores entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$2F&amp;lt;/code&amp;gt;. || — || No || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres de las etapas corresponden a los [https://github.com/IsoFrieze/SMWDisX/blob/master/bank_00.asm game modes de SMW documentados en SMWDisX]; los permisos se obtienen de las tablas de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Cuando &amp;lt;code&amp;gt;Upload&amp;lt;/code&amp;gt; no permite una solicitud nueva, comprueba si el recurso conserva una pose anterior. Si existe, actualiza su tiempo de último uso y devuelve carry activado; si no existe, devuelve carry desactivado. No solicita otra pose en ese camino.&lt;br /&gt;
&lt;br /&gt;
Los modos &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$29&amp;lt;/code&amp;gt; muestran por qué deben distinguirse ambas columnas: pasar la comprobación de sprites no habilita el NMI del sistema general ni evita que el game mode reinicialice sus variables. La columna de sprites no debe interpretarse como una garantía de funcionamiento completo en esos modos.&lt;br /&gt;
&lt;br /&gt;
=== Transferencias durante NMI ===&lt;br /&gt;
&lt;br /&gt;
NMI es una interrupción que SNES puede generar al comenzar VBlank, después de dibujar la parte visible de la pantalla. El juego aprovecha ese intervalo para actualizar gráficos, colores y otros datos de video.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;La CPU ejecuta tanto la lógica del juego como la rutina NMI.&#039;&#039;&#039; Durante la lógica del juego, mueve sprites y prepara las solicitudes de carga. Al comenzar VBlank, una interrupción NMI puede detener temporalmente esa lógica para ejecutar las actualizaciones de video. Cuando termina la rutina NMI, la CPU retoma el código que había interrumpido.&lt;br /&gt;
&lt;br /&gt;
Este es el recorrido habitual de un frame:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Momento !! Qué hace la CPU !! Qué ocurre con los gráficos&lt;br /&gt;
|-&lt;br /&gt;
| Lógica del juego&lt;br /&gt;
| Mueve sprites, selecciona poses, calcula efectos y prepara el dibujo.&lt;br /&gt;
| Las solicitudes aceptadas se guardan en las listas de transferencias.&lt;br /&gt;
|-&lt;br /&gt;
| VBlank, durante NMI&lt;br /&gt;
| Ejecuta la rutina NMI y configura las transferencias DMA.&lt;br /&gt;
| Se copian los gráficos a VRAM, los colores a CGRAM y los datos de OAM a su memoria correspondiente.&lt;br /&gt;
|-&lt;br /&gt;
| Al terminar NMI&lt;br /&gt;
| Retoma el código interrumpido.&lt;br /&gt;
| Los datos actualizados se utilizan al dibujar la siguiente imagen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La tabla resume el recorrido habitual; durante slowdown, SMW puede ejecutar un NMI reducido, como se explica en el apartado de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
En los modos permitidos, la rutina de Dynamic Xtreme realiza estas tareas en orden, según las funcionalidades habilitadas:&lt;br /&gt;
&lt;br /&gt;
# Pone &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; en 0 para contar las solicitudes del siguiente ciclo de lógica. Las transferencias ya preparadas siguen guardadas en sus listas.&lt;br /&gt;
# Incrementa &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Comprueba &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt;. Si ambos están en 0, incrementa &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ejecuta las transferencias pendientes a VRAM, si está habilitado &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ejecuta las transferencias pendientes a CGRAM, si está habilitado &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si está habilitado &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;, ejecuta la actualización del color 0,0 cuando hay un resultado pendiente.&lt;br /&gt;
&lt;br /&gt;
Para realizar las copias se utiliza DMA. NMI lee cada carga de las listas, configura desde dónde se copiarán los datos, cuántos bytes se copiarán y dónde se colocarán, y ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
El tiempo de VBlank es limitado y SMW también lo necesita para sus actualizaciones de pantalla. Para limitar la cantidad de datos enviados en un frame y evitar flickering, Dynamic Xtreme utiliza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, que cuenta los bytes de las cargas solicitadas, y &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, que establece el límite permitido. Antes de aceptar una carga normal, se comprueba que sus bytes no hagan superar ese límite.&lt;br /&gt;
&lt;br /&gt;
==== Las listas de transferencias ====&lt;br /&gt;
&lt;br /&gt;
Cada transferencia guarda el origen de los datos, su banco, la cantidad de bytes y el destino en VRAM o CGRAM.&lt;br /&gt;
&lt;br /&gt;
Al realizar las copias, NMI recorre las listas desde la última entrada hacia la primera y después las vacía. Esto no borra los gráficos o colores cargados: permanecen en su destino hasta que otro código los cambie.&lt;br /&gt;
&lt;br /&gt;
La lista de VRAM utiliza 0 cuando no tiene entradas. La de CGRAM utiliza &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, porque guarda el índice de la última entrada en lugar de guardar directamente su cantidad.&lt;br /&gt;
&lt;br /&gt;
Si dos códigos escriben sobre el mismo destino, deben coordinar sus cargas. El orden de las solicitudes no debe utilizarse como sustituto de decidir qué recurso puede ocupar cada espacio.&lt;br /&gt;
&lt;br /&gt;
Normalmente, el recurso se lee desde ROM. Si el recurso se encuentra en un buffer en RAM, el usuario debe conservar su contenido hasta que NMI realice la transferencia. Por ejemplo, si prepara una paleta en RAM, no debe modificar ni reutilizar ese buffer antes de que se copie. La lista guarda su dirección, no una copia de sus datos; Dynamic Xtreme no protege el buffer contra cambios realizados por otros códigos.&lt;br /&gt;
&lt;br /&gt;
==== Presupuesto de datos ====&lt;br /&gt;
&lt;br /&gt;
Las macros de transferencia, como &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt;, comprueban cuántos bytes se han solicitado mediante &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;. Si al añadir la nueva carga se supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, la rechazan. Si la aceptan, suman sus bytes al contador.&lt;br /&gt;
&lt;br /&gt;
El límite predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Su objetivo es evitar flickering por enviar demasiados datos en un mismo frame. Es un límite de cantidad de datos, no una medida exacta del tiempo que tarda cada transferencia.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; lleva la cuenta de los bytes solicitados. La comprobación &amp;lt;code&amp;gt;CurrentDataSend + bytes del recurso &amp;amp;gt; MaxDataPerFrame&amp;lt;/code&amp;gt; impide aceptar una carga normal que supere el presupuesto y limita así los datos que se transferirán durante VBlank.&lt;br /&gt;
&lt;br /&gt;
En las solicitudes de poses dinámicas, la falta de presupuesto y la falta de espacio utilizable en VRAM devuelven el mismo resultado de fallo. La llamada no indica cuál de las dos causas impidió la carga. Un fallo tampoco significa que se haya sobrecargado VBlank: si se debe al presupuesto, la carga se rechazó precisamente para evitar esa sobrecarga.&lt;br /&gt;
&lt;br /&gt;
Estas macros tienen variantes como &amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ForcedTransferToCGRAM()&amp;lt;/code&amp;gt;, que aceptan la carga sin comprobar si supera el límite. Sus bytes también se suman a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, por lo que reducen lo que queda disponible para las siguientes cargas normales. Se utilizan para cargas prioritarias, como las del jugador; usarlas no evita el flickering si se solicita una cantidad excesiva de datos.&lt;br /&gt;
&lt;br /&gt;
Para consultar la diferencia entre el presupuesto de bytes y la capacidad de las listas, las restricciones de las transferencias y las comprobaciones que debe realizar tu código, consulta [[es/Dynamic_Xtreme_ASM_API#PPU|PPU en la API ASM]].&lt;br /&gt;
&lt;br /&gt;
==== Los dos relojes ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_Timer: protección de las solicitudes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza cuando se ejecuta la parte de NMI de Dynamic Xtreme. Además de medir cuánto lleva una pose sin utilizarse, sirve para evitar que un recurso repita sus solicitudes antes de que se procesen las anteriores.&lt;br /&gt;
&lt;br /&gt;
No siempre hay un ciclo de lógica por cada ejecución completa de NMI. Durante slowdown, SMW puede ejecutar una versión reducida de NMI, y puede haber dos ciclos de lógica sin que entre ellos se hayan procesado las listas de transferencias de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Sin una protección, un recurso podría añadir otra vez sus cargas a esas listas. Las solicitudes repetidas ocuparían más espacio y podrían provocar flickering.&lt;br /&gt;
&lt;br /&gt;
Para evitarlo, las rutinas de carga de poses para sprites comparan &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; con el valor de dos bytes guardado por ese sprite, normalmente llamado &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt;. En los aliases de sprites se utiliza &amp;lt;code&amp;gt;!SafeFrameLowByte,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!SafeFrameHighByte,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El proceso es el siguiente:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Compara los relojes.&#039;&#039;&#039; Si &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; coincide con &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;, ese sprite ya procesó su carga de poses con ese valor del reloj. La rutina omite una nueva solicitud.&lt;br /&gt;
# &#039;&#039;&#039;Guarda el intento antes de procesarlo.&#039;&#039;&#039; Si los valores son distintos, copia &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; y después comprueba si puede reutilizar la pose o necesita solicitar otra.&lt;br /&gt;
# &#039;&#039;&#039;Comprueba el resultado.&#039;&#039;&#039; Si necesita una pose nueva, la solicitud puede aceptarse o rechazarse. Aunque sea rechazada, el valor guardado en &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; no se deshace.&lt;br /&gt;
&lt;br /&gt;
Por tanto, &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; indica &#039;&#039;&#039;cuándo se procesó el último intento&#039;&#039;&#039;, no cuándo se consiguió cargar una pose. Si la carga falla, volver a ejecutar la rutina con el mismo &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; no permite intentarla otra vez, aunque entre ambas llamadas haya cambiado la pose deseada o el espacio disponible.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;, tanto una solicitud rechazada como una llamada omitida por esta protección utilizan el mismo camino de respaldo:&lt;br /&gt;
&lt;br /&gt;
* Si &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; es distinto de &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, actualizan el tiempo de último uso de esa pose para protegerla del reemplazo y devuelven carry activado. El sprite puede seguir dibujando la última pose disponible.&lt;br /&gt;
* Si contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no existe una pose de respaldo y devuelven carry desactivado.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, durante slowdown puede ocurrir esta secuencia:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;DX_Timer = $0030&amp;lt;/code&amp;gt;. El sprite guarda &amp;lt;code&amp;gt;$0030&amp;lt;/code&amp;gt; en su &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; e intenta obtener una pose nueva. No queda presupuesto de datos y la solicitud falla; conserva la pose anterior si tiene una.&lt;br /&gt;
# SMW ejecuta otro ciclo de lógica sin que se haya procesado el NMI de Dynamic Xtreme. El reloj sigue en &amp;lt;code&amp;gt;$0030&amp;lt;/code&amp;gt;. La siguiente llamada del mismo sprite detecta la coincidencia y no repite la solicitud.&lt;br /&gt;
# Cuando se ejecuta el NMI de Dynamic Xtreme, &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza a &amp;lt;code&amp;gt;$0031&amp;lt;/code&amp;gt;. En la siguiente llamada, los relojes ya no coinciden y el sprite puede volver a intentarlo. La solicitud rechazada no se reintenta sola: el código del sprite debe volver a llamar a la rutina.&lt;br /&gt;
&lt;br /&gt;
Esta protección está activada en los aliases de carga de poses para sprites. En [[es/Dynamic_Xtreme_ASM_API#GeneralUpload|GeneralUpload]] y [[es/Dynamic_Xtreme_ASM_API#Upload (macro general)|Upload (macro general)]] se controla con &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt;; el respaldo de la pose anterior se controla por separado con &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt;. [[es/Dynamic_Xtreme_ASM_API#TakeDynamicRequest|TakeDynamicRequest]] y las [[es/Dynamic_Xtreme_ASM_API#PPU|macros de transferencia PPU]] no realizan esta comprobación de &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; por ti.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; continúa avanzando durante la pausa cuando se ejecuta esa parte de NMI.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_SyncTimer: animaciones sincronizadas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
La función principal de &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; es dar a los sprites un reloj común para sus animaciones. Por ejemplo, varios sprites que utilizan las mismas poses pueden calcular con este reloj qué pose les corresponde cada cuatro frames.&lt;br /&gt;
&lt;br /&gt;
Así todos cambian al mismo tiempo y solicitan la misma pose. La primera solicitud puede necesitar cargarla; las demás la reutilizan sin programar otra carga de sus gráficos. Esto ahorra transferencias DMA y datos enviados por frame.&lt;br /&gt;
&lt;br /&gt;
Si cada sprite llevara un reloj independiente, podrían terminar usando poses distintas de la misma animación al mismo tiempo y necesitar más cargas y espacio de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; se detiene durante la pausa y cuando se congela la acción, para que las animaciones sincronizadas también se detengan.&lt;br /&gt;
&lt;br /&gt;
== Carga de gráficos: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; guarda en RAM una lista de solicitudes de carga. Durante NMI se recorren esas solicitudes y se copian sus datos a VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Variables de la lista ===&lt;br /&gt;
&lt;br /&gt;
En esta tabla, &#039;&#039;&#039;V&#039;&#039;&#039; es el valor de &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt;: 64 por defecto. Las cuatro tablas de solicitudes reservan V bytes cada una; con entradas de 2 bytes, ese valor deja espacio para 32 solicitudes. Junto con el contador, reservan &amp;lt;code&amp;gt;1 + 4 × V&amp;lt;/code&amp;gt; bytes: 257 por defecto.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de solicitudes pendientes. El valor 0 indica que la lista está vacía.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Dirección de origen de cada solicitud, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 reservados; banco de 1 byte || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Cantidad de bytes que se copiarán.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Dirección de destino en VRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las tablas mantienen el mismo orden: la primera entrada de cada tabla pertenece a la primera solicitud, la segunda a la segunda, etc. Cada entrada de estas tablas ocupa 2 bytes, por lo que se avanza con desplazamientos de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt;, etc.&lt;br /&gt;
&lt;br /&gt;
Estos nombres representan direcciones de RAM calculadas en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus direcciones pueden cambiar según la configuración y las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
=== Añadir una solicitud ===&lt;br /&gt;
&lt;br /&gt;
La macro &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; realiza los siguientes pasos:&lt;br /&gt;
&lt;br /&gt;
# Calcula cuántos bytes habría en total al añadir la nueva carga a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Compara el resultado con &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;. Si lo supera, devuelve el carry desactivado y no añade la solicitud.&lt;br /&gt;
# Utiliza &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para encontrar la siguiente entrada y aumenta ese contador en 1.&lt;br /&gt;
# Guarda el origen, banco, cantidad de bytes y destino en las tablas.&lt;br /&gt;
# Actualiza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; con los bytes de la carga y devuelve el carry activado.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; guarda los mismos datos, pero no comprueba el límite de bytes. Las variantes &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; facilitan obtener el origen desde una dirección completa o desde los defines de un recurso.&lt;br /&gt;
&lt;br /&gt;
Añadir una solicitud no copia los gráficos inmediatamente: deja la información preparada para NMI.&lt;br /&gt;
&lt;br /&gt;
=== Ejecutar las solicitudes durante NMI ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Lee &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;. Si es 0, termina porque no hay solicitudes.&lt;br /&gt;
# Calcula el desplazamiento de la última entrada: &amp;lt;code&amp;gt;(Length - 1) × 2&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Lee su origen, banco y cantidad de bytes, y los coloca en los registros de DMA.&lt;br /&gt;
# Escribe el destino de VRAM en &amp;lt;code&amp;gt;$2116-$2117&amp;lt;/code&amp;gt; e inicia la transferencia mediante &amp;lt;code&amp;gt;$420B&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Retrocede 2 bytes para procesar la solicitud anterior. Repite hasta completar la primera.&lt;br /&gt;
# Escribe 0 en &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para indicar que la lista está vacía.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;La lista se ejecuta del final al inicio.&#039;&#039;&#039; No hace falta borrar todos sus datos al terminar: al quedar su largo en 0, la próxima solicitud volverá a utilizar la primera entrada.&lt;br /&gt;
&lt;br /&gt;
=== Animaciones con un destino fijo ===&lt;br /&gt;
&lt;br /&gt;
El código de una animación debe:&lt;br /&gt;
&lt;br /&gt;
# Elegir la imagen que corresponde al paso actual.&lt;br /&gt;
# Calcular su dirección de origen.&lt;br /&gt;
# Solicitar la copia al destino de VRAM de la animación.&lt;br /&gt;
# Comprobar el carry. Si se rechaza la carga, conservar la imagen anterior y volver a intentarlo.&lt;br /&gt;
&lt;br /&gt;
El destino puede ser siempre el mismo. Lo que cambia es la imagen que se copia allí; la lista de transferencias no decide cuándo debe avanzar la animación.&lt;br /&gt;
&lt;br /&gt;
Puedes ver un código completo en [[es/Dynamic_Xtreme_UberASM_guide#Crear_animaciones_de_gráficos|Crear animaciones de gráficos de la guía de UberASM]].&lt;br /&gt;
&lt;br /&gt;
=== Carga de una pose dinámica ===&lt;br /&gt;
&lt;br /&gt;
La carga de una pose utiliza la caché para no repetir transferencias de gráficos que ya están disponibles:&lt;br /&gt;
&lt;br /&gt;
# Busca el ID en la tabla hash.&lt;br /&gt;
# Si ya está registrado, actualiza su tiempo de uso y no añade otra carga.&lt;br /&gt;
# Si no está, comprueba la cantidad de bytes y busca un espacio adecuado en el mapa de VRAM.&lt;br /&gt;
# Elige qué poses pueden reemplazarse, teniendo en cuenta su tiempo sin uso y el espacio que necesita la nueva.&lt;br /&gt;
# Actualiza las tablas de la caché y el mapa.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; divide los datos de la pose en las transferencias necesarias.&lt;br /&gt;
# NMI ejecuta esas transferencias.&lt;br /&gt;
&lt;br /&gt;
Cada paso se desarrolla en [[#Sprites_dinámicos:_DynamicPoses|Sprites dinámicos: DynamicPoses]], incluyendo la búsqueda por hash, el mapa, la política de reemplazo y la división de la carga en filas.&lt;br /&gt;
&lt;br /&gt;
== Carga y asignación de paletas: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
El sistema distingue dos valores:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID de paleta:&#039;&#039;&#039; identifica los colores guardados en ROM.&lt;br /&gt;
* &#039;&#039;&#039;Color de destino:&#039;&#039;&#039; indica desde qué color de la paleta de colores de CGRAM se colocarán los colores que se carguen. Por ejemplo, &amp;lt;code&amp;gt;$91&amp;lt;/code&amp;gt; comienza en el color 1 de la paleta 9.&lt;br /&gt;
&lt;br /&gt;
La asignación automática permite compartir colores entre sprites sin exigir un destino fijo para cada uno.&lt;br /&gt;
&lt;br /&gt;
=== Lista de cargas a CGRAM ===&lt;br /&gt;
&lt;br /&gt;
En esta tabla, &#039;&#039;&#039;C&#039;&#039;&#039; es &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt;: 64 por defecto. El conjunto reserva &amp;lt;code&amp;gt;1 + 7 × C&amp;lt;/code&amp;gt; bytes, es decir, 449 con ese valor. Aunque &amp;lt;code&amp;gt;SourceBNK&amp;lt;/code&amp;gt; reserva 2 × C bytes, el código utiliza un byte de banco por solicitud.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Índice de la última solicitud pendiente. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; indica una lista vacía; 0 indica que hay una solicitud.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || 2 × C; 128 por defecto || 2 || Dirección de origen, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || 2 × C; 128 reservados por defecto || 1 utilizado por solicitud || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || 2 × C; 128 por defecto || 2 || Cantidad de bytes que se copiarán. Cada color ocupa 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || C; 64 por defecto || 1 || Primer color de destino en CGRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Durante NMI, &amp;lt;code&amp;gt;CGRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Comienza por la última solicitud pendiente.&lt;br /&gt;
# Configura DMA con el origen y la cantidad de bytes de esa solicitud.&lt;br /&gt;
# Selecciona el primer color mediante &amp;lt;code&amp;gt;$2121&amp;lt;/code&amp;gt; y realiza la copia.&lt;br /&gt;
# Continúa con las solicitudes anteriores.&lt;br /&gt;
# Al terminar, escribe &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; también actualizan las copias de colores y el estado de efectos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Sin efecto global:&#039;&#039;&#039; solicitan la carga y actualizan los buffers de SMW. Así el juego no vuelve a utilizar colores anteriores durante la animación de victoria del goal.&lt;br /&gt;
* &#039;&#039;&#039;Con efecto global:&#039;&#039;&#039; guardan los colores originales y preparan el estado necesario para aplicarles el efecto antes de enviarlos a CGRAM.&lt;br /&gt;
&lt;br /&gt;
=== Asignación automática ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 32 || 2 || Guarda el ID asignado a cada destino. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre y &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; una reservada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 16 || 1 || Protege cada destino del reemplazo automático mientras está en uso.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta de sprites || Indica qué paletas de sprites están asignadas con efecto global habilitado. Esta condición también se compara al compartir una asignación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue este orden:&lt;br /&gt;
&lt;br /&gt;
# Reutilizar una asignación con el mismo ID y una condición de efecto compatible.&lt;br /&gt;
# Si no existe, utilizar una entrada libre.&lt;br /&gt;
# Si no hay entradas libres, reemplazar una que no esté reservada y cuyo temporizador sea 0.&lt;br /&gt;
# Si no encuentra ninguna, indicar que la asignación falló.&lt;br /&gt;
&lt;br /&gt;
Mientras el recurso utiliza la paleta, mantiene su temporizador en 2. Llegar a 0 no borra los colores: la asignación puede reutilizarse si otro recurso todavía no la reemplazó.&lt;br /&gt;
&lt;br /&gt;
=== Asignación manual y versión ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Manual con carga:&#039;&#039;&#039; el código elige el destino y solicita sus colores.&lt;br /&gt;
* &#039;&#039;&#039;Manual sin carga:&#039;&#039;&#039; el código elige el destino y utiliza los colores que ya estaban preparados.&lt;br /&gt;
* &#039;&#039;&#039;Versión:&#039;&#039;&#039; selecciona una entrada de la lista de paletas del DynamicInfo. La última versión procesada permite comprobar si esa selección cambió.&lt;br /&gt;
&lt;br /&gt;
Dos recursos que elijan el mismo destino con colores distintos deben coordinarse. Mantener la protección de una paleta no significa volver a cargar sus colores.&lt;br /&gt;
&lt;br /&gt;
== Dibujo de poses: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
El dibujo prepara las piezas de una pose en OAM: qué tiles se muestran, dónde se colocan y qué propiedades utilizan. Los datos gráficos deben estar en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Pasos del dibujo ===&lt;br /&gt;
&lt;br /&gt;
# Busca la rutina y los datos de la pose mediante &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Obtiene la cantidad de piezas desde &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Calcula la posición de cada tile usando la posición del sprite, sus desplazamientos y los volteos que correspondan.&lt;br /&gt;
# Comprueba si la pieza puede verse y si queda espacio de OAM.&lt;br /&gt;
# Escribe su posición, número de tile, propiedades y tamaño en los buffers OAM.&lt;br /&gt;
&lt;br /&gt;
El número de tile depende del dibujo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Cómo se obtiene el tile&lt;br /&gt;
|-&lt;br /&gt;
| Pose dinámica || Se ajusta al lugar de VRAM donde quedaron cargados sus gráficos.&lt;br /&gt;
|-&lt;br /&gt;
| Pose estática || Se utiliza su número de tile fijo.&lt;br /&gt;
|-&lt;br /&gt;
| Pose que utiliza un tile común || El código debe preparar &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; antes de llamar al dibujo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Prioridad y espacio disponible ===&lt;br /&gt;
&lt;br /&gt;
* En &#039;&#039;&#039;LoROM&#039;&#039;&#039;, el sistema lleva su propio control de entradas OAM disponibles.&lt;br /&gt;
* En &#039;&#039;&#039;SA-1&#039;&#039;&#039;, utiliza la integración con MaxTile.&lt;br /&gt;
* La &#039;&#039;&#039;prioridad de dibujo&#039;&#039;&#039; organiza las piezas de sprites. No es la misma propiedad que determina si un tile queda delante o detrás de las capas.&lt;br /&gt;
* Los &#039;&#039;&#039;límites por línea de pantalla&#039;&#039;&#039; de SNES siguen existiendo. Tener una pose cargada no garantiza que puedan verse todas sus piezas.&lt;br /&gt;
&lt;br /&gt;
== Jugador y Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
El jugador original tiene rutinas propias para elegir y cargar las piezas de sus poses. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; permite integrar ese trabajo con las cargas de Dynamic Xtreme y cambiar el origen de sus gráficos y paletas.&lt;br /&gt;
&lt;br /&gt;
Con el formato original, el juego sigue eligiendo las piezas de la pose. La rutina obtiene sus direcciones desde el origen configurado y compara esas direcciones con las anteriores para cargar las que hayan cambiado.&lt;br /&gt;
&lt;br /&gt;
Estas cargas utilizan transferencias forzadas y sus bytes también cuentan para las solicitudes normales posteriores. Así conservan su prioridad sin quedar fuera de la contabilidad del sistema.&lt;br /&gt;
&lt;br /&gt;
La paleta del jugador tiene un tratamiento especial: combina colores y selecciones del propio juego con el origen personalizado. No funciona simplemente como sustituir una paleta completa de un sprite cualquiera.&lt;br /&gt;
&lt;br /&gt;
El soporte para jugadores personalizados permite que otros sistemas administren de otra forma sus poses y dibujo. No convierte automáticamente cualquier spritesheet al formato del jugador original.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi también carga sus gráficos por piezas. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; permite cambiar su origen manteniendo la organización que esperan sus rutinas.&lt;br /&gt;
&lt;br /&gt;
El código calcula qué partes necesita y prepara sus cargas a los destinos correspondientes de VRAM. Como las del jugador, estas cargas tienen un tratamiento prioritario.&lt;br /&gt;
&lt;br /&gt;
Esta opción necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad. No permite evitar un conflicto del sistema del jugador habilitando únicamente las funciones de Yoshi.&lt;br /&gt;
&lt;br /&gt;
== Diferencias entre LoROM y SA-1 ==&lt;br /&gt;
&lt;br /&gt;
Las principales diferencias de Dynamic Xtreme entre ambas configuraciones están en la memoria utilizada para sus variables y en el sistema de dibujo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Aspecto !! LoROM !! SA-1&lt;br /&gt;
|-&lt;br /&gt;
| Memoria para las variables&lt;br /&gt;
| Se suele utilizar &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; para aprovechar la RAM recuperada como espacio para las variables de Dynamic Xtreme. Si esta opción provoca problemas de compatibilidad, puede deshabilitarse y utilizar la configuración alternativa, con el espacio de RAM más ajustado.&lt;br /&gt;
| No utiliza &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;. Las áreas principales de variables se encuentran en BW-RAM, en los bancos &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$41&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Prioridades de dibujo&lt;br /&gt;
| Utiliza el sistema propio de Dynamic Xtreme, con dos prioridades de dibujo.&lt;br /&gt;
| Utiliza MaxTile, con cuatro prioridades de dibujo para los tiles.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las dos prioridades de LoROM no permiten mantener todas las distinciones de orden de las cuatro prioridades de SA-1. Por eso, algunos recursos que se dibujan correctamente en SA-1 pueden presentar un orden de dibujo diferente o incorrecto en LoROM. Estas prioridades organizan los tiles de sprites; no son la prioridad que determina si aparecen delante o detrás de las capas.&lt;br /&gt;
&lt;br /&gt;
Los rangos de RAM de cada configuración se detallan en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
== Memoria y optimizaciones ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW mantiene en RAM gráficos originales del jugador, Yoshi y ciertas animaciones. En ROMs sin SA-1, esta opción adapta las cargas para leer esos datos desde ROM.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aprovecha la RAM recuperada para sus variables internas. No es un espacio que quede libre para que cualquier otro código escriba encima.&lt;br /&gt;
&lt;br /&gt;
SA-1 utiliza otras direcciones y desactiva esta opción. Los rangos están en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
Esta opción mueve el procesamiento del control desde NMI a la parte de game mode. El objetivo es dejar más tiempo para las actualizaciones de pantalla, no añadir un frame de retraso ni cambiar los botones que recibe el juego.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
El color fijo se utiliza en las mezclas de color de la consola. Para actualizarlo, el juego prepara sus componentes y los envía al registro correspondiente.&lt;br /&gt;
&lt;br /&gt;
La optimización reemplaza esa preparación por una secuencia más corta. El color sigue enviándose a la consola, pero necesita menos trabajo durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic utiliza listas llamadas stripe images para actualizar partes de los mapas de tiles. Esas listas incluyen tanto los datos como la información sobre sus destinos.&lt;br /&gt;
&lt;br /&gt;
La versión integrada de la optimización de Kevin prepara fuera de NMI parte del ajuste de esos destinos. Así deja menos trabajo de preparación para el momento de la transferencia.&lt;br /&gt;
&lt;br /&gt;
Esta opción sustituye el uso del parche original por separado. Además, no debe desinstalarse después de instalarla; hay que tenerlo en cuenta antes de activarla.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
La barra de estado original actualiza zonas concretas de VRAM. Esta opción prepara sus transferencias de forma más directa, reduciendo la configuración de DMA que necesita hacer durante NMI.&lt;br /&gt;
&lt;br /&gt;
No añade una barra nueva. Modifica la actualización de la original y, por eso, entra en conflicto con recursos que la reemplazan, modifican o eliminan.&lt;br /&gt;
&lt;br /&gt;
== Sprites dinámicos: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
El sistema funciona como una &#039;&#039;&#039;caché de poses en VRAM&#039;&#039;&#039;. No reserva una copia de los gráficos para cada sprite: guarda la pose y permite que la reutilicen todos los recursos que la necesiten.&lt;br /&gt;
&lt;br /&gt;
* Una pose se carga una sola vez mientras permanezca en la caché.&lt;br /&gt;
* Las siguientes solicitudes actualizan su tiempo de último uso, sin añadir otra carga de sus gráficos.&lt;br /&gt;
* La pose no se borra cuando un recurso deja de utilizarla. Permanece allí hasta que se necesite su espacio y se elija reemplazarla.&lt;br /&gt;
* Si fue reemplazada y vuelve a solicitarse, tendrá que cargarse otra vez.&lt;br /&gt;
&lt;br /&gt;
La elección no depende de cuánto tiempo lleva la pose desde que se cargó, sino de &#039;&#039;&#039;cuánto tiempo lleva sin utilizarse&#039;&#039;&#039; y de si su espacio sirve para la pose nueva.&lt;br /&gt;
&lt;br /&gt;
=== Tres valores distintos ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Qué identifica&lt;br /&gt;
|-&lt;br /&gt;
| ID de pose || La pose instalada. Tiene 16 bits y permite consultar sus datos en ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Índice de la tabla hash || La entrada de RAM donde se registró la pose. Va de 0 a 127.&lt;br /&gt;
|-&lt;br /&gt;
| Bloque de VRAM || ID de una de las 128 posiciones para tiles de 16×16 que caben en el espacio de VRAM de sprites. Se numeran de izquierda a derecha y de arriba abajo, desde 0 hasta 127. Para una pose que ocupa varios bloques, se guarda el ID de su primer bloque.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
El índice de la tabla hash y el bloque de VRAM no tienen por qué coincidir. Una entrada de la tabla puede registrar una pose que empieza en cualquier bloque permitido.&lt;br /&gt;
&lt;br /&gt;
=== Tablas de las poses registradas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de poses registradas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 || 1 || Cantidad de poses registradas para cada hash.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 256 || 2 || ID completo de la pose de cada entrada. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Bloque de VRAM donde comienza cada pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 256 || 2 || Valor de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; de su último uso.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas ocupan &#039;&#039;&#039;769 bytes&#039;&#039;&#039; en RAM. Guardan las poses registradas durante el juego; las tablas generadas desde el DynamicInfo describen, en cambio, todas las poses instaladas.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se busca una pose ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;DynamicPoseHashmap_FindPose&amp;lt;/code&amp;gt; utiliza una tabla hash de 128 entradas. El hash permite elegir dónde empezar a buscar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hash = ID de pose AND $007F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dos IDs diferentes pueden tener el mismo hash. Por ejemplo, &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; producen &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;. Por eso el hash no basta para confirmar que la pose está cargada: también se compara el ID completo.&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue estos pasos:&lt;br /&gt;
&lt;br /&gt;
# Guarda el ID solicitado y calcula su hash.&lt;br /&gt;
# Si &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; es 0, no hay poses registradas y la búsqueda termina.&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize[hash]&amp;lt;/code&amp;gt;. Si es 0, ninguna pose registrada tiene ese hash y también termina.&lt;br /&gt;
# Comienza por la entrada cuyo índice coincide con el hash.&lt;br /&gt;
# Lee el ID de esa entrada. Si coincide con el solicitado, encontró la pose.&lt;br /&gt;
# Si no coincide, continúa con la siguiente entrada de la secuencia de búsqueda.&lt;br /&gt;
&lt;br /&gt;
La secuencia avanza &#039;&#039;&#039;15 entradas por intento&#039;&#039;&#039; y vuelve al comienzo al superar 127:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
siguiente índice = (índice actual + 15) AND $7F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Con 128 entradas, ese paso permite visitar todas las posiciones antes de repetir una. Para el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, el comienzo de la secuencia es:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$05 → $14 → $23 → $32 → $41 → ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== El contador de poses de cada hash ====&lt;br /&gt;
&lt;br /&gt;
Cada hash tiene su propio contador en &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt;. Por ejemplo, si hay dos poses registradas cuyo ID produce el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, la entrada &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize+$05&amp;lt;/code&amp;gt; contiene 2.&lt;br /&gt;
&lt;br /&gt;
Ese número indica &#039;&#039;&#039;cuántas poses con ese hash existen&#039;&#039;&#039;, no cuántas posiciones hay que recorrer. La búsqueda utiliza una copia temporal del contador:&lt;br /&gt;
&lt;br /&gt;
# Comienza con la cantidad de poses registrada para el hash solicitado.&lt;br /&gt;
# Recorre las posiciones de la secuencia hasta encontrar el ID solicitado o haber comprobado esa cantidad de poses con el mismo hash.&lt;br /&gt;
# Cada vez que encuentra una pose con ese hash, pero con otro ID, resta 1 al contador temporal.&lt;br /&gt;
# Las posiciones libres y las poses de otros hashes no descuentan nada: continúa buscando.&lt;br /&gt;
# Si el contador temporal llega a 0 sin encontrar el ID, la pose solicitada no está registrada y la búsqueda termina.&lt;br /&gt;
&lt;br /&gt;
El contador de &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; no se modifica durante esta búsqueda. Solo se actualiza al añadir o retirar poses de la caché.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, se busca &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt;, que produce el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, y el contador de ese hash vale 2:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Posición visitada !! ID guardado !! Hash del ID !! Poses del hash $05 que faltan por comprobar&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 1: tiene el mismo hash, pero no es el ID solicitado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0014&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || 1: es otro hash, así que no se descuenta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$23&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 0: ya se comprobaron las dos poses con ese hash. &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt; no está registrada.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Lo habitual es que haya una o dos poses por hash. Esto permite resolver la búsqueda con pocas comprobaciones y un coste normalmente cercano a &amp;lt;code&amp;gt;O(1)&amp;lt;/code&amp;gt;. No significa que siempre se visiten solo una o dos posiciones: puede haber entradas de otros hashes entre ellas. Con muchas colisiones, el recorrido puede ser más largo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Una entrada libre no termina la búsqueda.&#039;&#039;&#039; Puede haber quedado vacía al reemplazar una pose y existir otra del mismo hash más adelante. El contador permite saber cuándo ya se comprobaron todas las poses de ese hash, incluso si hay huecos entre ellas.&lt;br /&gt;
&lt;br /&gt;
==== Cuando encuentra la pose ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Obtiene el índice de la entrada encontrada.&lt;br /&gt;
# Escribe el valor actual de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; para esa entrada.&lt;br /&gt;
# Devuelve el éxito de la solicitud, sin volver a programar la carga de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
Así todos los recursos que solicitan ese ID utilizan la misma pose y la mantienen protegida. No importa si el recurso es un sprite normal, cluster, extended u otro código que utiliza el sistema.&lt;br /&gt;
&lt;br /&gt;
Esto también evita duplicar una carga dentro del mismo ciclo: cuando la primera solicitud se acepta, la pose ya queda registrada aunque la transferencia física se vaya a realizar durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== Cuando la pose no está registrada ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt; continúa con la preparación de una carga nueva:&lt;br /&gt;
&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; y calcula &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend + PoseSize&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, termina con fallo, sin cambiar las poses existentes.&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; para saber cuántos bloques necesita.&lt;br /&gt;
# Llama a &amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; para buscar un espacio adecuado.&lt;br /&gt;
# Si no existe un espacio utilizable, termina con fallo.&lt;br /&gt;
# Retira del mapa y de la tabla hash las poses que ocupen el espacio elegido.&lt;br /&gt;
# Busca una entrada libre de la tabla hash y registra la pose nueva.&lt;br /&gt;
# Actualiza el mapa de VRAM y el contador de datos del frame.&lt;br /&gt;
# Llama a &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; para añadir las transferencias.&lt;br /&gt;
&lt;br /&gt;
El presupuesto se comprueba antes de reemplazar poses. Si la nueva carga no cabe en el frame, no se libera espacio para una solicitud que no se puede atender.&lt;br /&gt;
&lt;br /&gt;
==== Añadir y quitar entradas de la tabla hash ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_FindFreeSpace&amp;lt;/code&amp;gt; busca una entrada cuyo ID sea &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt;, siguiendo la misma secuencia de pasos de 15.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; guarda el ID y su tiempo de uso, aumenta &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; y aumenta el contador de su hash.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Remove&amp;lt;/code&amp;gt; escribe &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; en el ID retirado y reduce ambos contadores.&lt;br /&gt;
&lt;br /&gt;
Retirar una entrada no borra por sí solo los píxeles de VRAM. Indica que esa pose dejó de estar disponible en la caché; las nuevas transferencias sobrescribirán el espacio elegido.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se representa el mapa de VRAM ===&lt;br /&gt;
&lt;br /&gt;
El mapa representa &#039;&#039;&#039;128 posiciones de tiles de 16×16 en la VRAM de sprites&#039;&#039;&#039;, numeradas de izquierda a derecha y de arriba abajo. Cada bloque es una de esas posiciones, no un tramo de 128 bytes contiguos.&lt;br /&gt;
&lt;br /&gt;
Un tile de 16×16 está formado por cuatro tiles de 8×8 distribuidos en dos filas. El mapa administra las posiciones que ocupa la pose; la distribución de sus datos para cargarlos se resuelve después en &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Posición donde comienza la sección. El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica que está restringida: ese espacio no se utiliza para poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt;, también llamada &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 || 1 || Si el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; está activo, los otros bits guardan la cantidad de posiciones de la sección menos uno. Si está desactivado, guardan el índice hash de la pose que ocupa la sección. Para saber si el espacio está restringido, se consulta &amp;lt;code&amp;gt;Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas dos tablas ocupan &#039;&#039;&#039;256 bytes&#039;&#039;&#039;. Junto con las tablas de poses, el administrador utiliza &#039;&#039;&#039;1025 bytes&#039;&#039;&#039; de RAM, sin contar las listas de transferencias ni las scratch de trabajo.&lt;br /&gt;
&lt;br /&gt;
=== Secciones del mapa ===&lt;br /&gt;
&lt;br /&gt;
Una sección agrupa posiciones consecutivas del mapa que están restringidas, libres o utilizadas por una pose. Su información se guarda en &#039;&#039;&#039;la primera y la última posición&#039;&#039;&#039;. Esto permite saltar de una sección a la anterior sin revisar todas sus posiciones intermedias.&lt;br /&gt;
&lt;br /&gt;
Los siguientes ejemplos muestran tres estados posibles para una sección de 6 posiciones, de &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;. Son casos alternativos, no tres secciones que ocupen el mismo espacio a la vez.&lt;br /&gt;
&lt;br /&gt;
==== Ejemplo 1: sección restringida ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Entradas de las tablas !! Valor !! Significado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$A0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica restringida y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; indica dónde comienza.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$85&amp;lt;/code&amp;gt; || La sección tiene 6 posiciones: &amp;lt;code&amp;gt;($85 AND $7F) + 1 = 6&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Aunque el bit alto de &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt; esté activo, &#039;&#039;&#039;no es espacio libre para poses dinámicas&#039;&#039;&#039;: el bit de restricción en &amp;lt;code&amp;gt;Offset&amp;lt;/code&amp;gt; hace que se descarte. No se evalúa como una pose que pueda reemplazarse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; utiliza este tipo de sección para excluir las partes de SP1-SP4 que no deben utilizar los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
==== Ejemplo 2: sección libre ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Entradas de las tablas !! Valor !! Significado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || Comienza en &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; y no está restringida.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$85&amp;lt;/code&amp;gt; || El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica el tamaño de una sección libre: &amp;lt;code&amp;gt;$05 + 1 = 6&amp;lt;/code&amp;gt; posiciones.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Esta sección sí está disponible. Puede alojar una pose que necesite hasta 6 posiciones; si se coloca una de 4, las otras 2 quedan como otra sección libre.&lt;br /&gt;
&lt;br /&gt;
==== Ejemplo 3: sección utilizada por una pose ====&lt;br /&gt;
&lt;br /&gt;
Supongamos que una pose de 6 bloques está registrada en la entrada hash &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; y ocupa las posiciones &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Entradas de las tablas !! Valor !! Significado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || La sección comienza en &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; y no está restringida.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; está desactivado: &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; es el índice hash de la pose, no su cantidad de bloques.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para conocer la cantidad de posiciones y el tiempo sin uso:&lt;br /&gt;
&lt;br /&gt;
# Se lee el ID de la pose en &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID+$0E&amp;lt;/code&amp;gt;. Se utiliza &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; porque cada ID ocupa 2 bytes y &amp;lt;code&amp;gt;$07 × 2 = $0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Con ese ID se consulta &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt;, que en este ejemplo contiene 6.&lt;br /&gt;
# Se consulta &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse+$0E&amp;lt;/code&amp;gt; para calcular cuánto lleva sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
La entrada &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset+$07&amp;lt;/code&amp;gt; guarda &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;, relacionando esa pose registrada con su posición en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Recorrido y búsqueda de espacio ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; comienza por la posición de tile de 16×16 &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt;. Para recorrer el mapa:&lt;br /&gt;
&lt;br /&gt;
# Lee &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; de la posición actual.&lt;br /&gt;
# Obtiene el comienzo de la sección con &amp;lt;code&amp;gt;Offset AND $7F&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Evalúa esa sección y los espacios que pueda formar con otras secciones contiguas.&lt;br /&gt;
# Pasa a la posición &amp;lt;code&amp;gt;comienzo de la sección - 1&amp;lt;/code&amp;gt;, que es la última posición de la sección anterior.&lt;br /&gt;
# Repite hasta llegar al comienzo del mapa.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si las últimas secciones comienzan en &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Posición visitada !! Comienzo leído de Offset !! Próxima posición&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4F&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Así recorre &#039;&#039;&#039;secciones completas&#039;&#039;&#039;, no cada tile intermedio.&lt;br /&gt;
&lt;br /&gt;
==== Qué se evalúa durante el recorrido ====&lt;br /&gt;
&lt;br /&gt;
El espacio candidato puede ser &#039;&#039;&#039;una sección o varias secciones contiguas&#039;&#039;&#039;. En cada paso se comprueba:&lt;br /&gt;
&lt;br /&gt;
* Si hay una sección restringida, no se utiliza ni se combina a través de ella.&lt;br /&gt;
* Si hay una pose protegida por su uso reciente, tampoco puede formar parte del espacio.&lt;br /&gt;
* Si el candidato todavía es pequeño, se puede continuar con una sección contigua para completar la cantidad de bloques necesaria.&lt;br /&gt;
* Si ya cabe la pose, se compara el candidato con el mejor encontrado: primero por su score de tiempo sin uso y después por el espacio suficiente más pequeño.&lt;br /&gt;
&lt;br /&gt;
No se elige una sección solo por contener la pose con más tiempo sin uso. El &#039;&#039;&#039;espacio completo&#039;&#039;&#039; debe permitir cargar la pose nueva. La puntuación de varias secciones combinadas depende de la pose utilizada más recientemente dentro de ese espacio.&lt;br /&gt;
&lt;br /&gt;
Durante la búsqueda se conservan estos datos temporales:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos de trabajo !! Bytes totales !! Bytes por valor !! Para qué se usan&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapCurrentSpace&amp;lt;/code&amp;gt; || 3 || 1 por campo || Comienzo, score y cantidad de bloques del espacio candidato actual.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapBestSpace&amp;lt;/code&amp;gt; || 3 || 1 por campo || Los mismos campos para el mejor espacio encontrado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapTMP_Size&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de bloques que necesita la pose nueva.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos nombres utilizan scratch de trabajo, no RAM persistente adicional.&lt;br /&gt;
&lt;br /&gt;
=== Política de reemplazo: tiempo sin uso y espacio suficiente ===&lt;br /&gt;
&lt;br /&gt;
El sistema no elige simplemente la pose que se cargó primero. Utiliza el tiempo transcurrido desde su &#039;&#039;&#039;último uso&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tiempo sin uso = DX_Timer - TimeLastUse de la pose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMapSlot_GetSizeAndScore&amp;lt;/code&amp;gt; obtiene el tamaño y una puntuación para cada región:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Puntuación y tratamiento&lt;br /&gt;
|-&lt;br /&gt;
| Región libre || &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Se favorece frente a regiones ocupadas.&lt;br /&gt;
|-&lt;br /&gt;
| Región ocupada || Tiempo sin uso, limitado a &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Tiempo sin uso de 0 o 1 || No se puede reemplazar: la pose sigue protegida.&lt;br /&gt;
|-&lt;br /&gt;
| Región restringida || Se descarta: ese espacio no se utiliza para poses dinámicas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La protección exige &#039;&#039;&#039;al menos dos avances de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; sin utilizar la pose&#039;&#039;&#039;. Cada recurso que vuelve a solicitarla actualiza su tiempo de uso y vuelve a protegerla.&lt;br /&gt;
&lt;br /&gt;
==== Por qué no siempre se reemplaza la pose con más tiempo sin uso ====&lt;br /&gt;
&lt;br /&gt;
La pose nueva necesita espacio suficiente y contiguo. Un espacio pequeño no sirve por sí solo, aunque lleve mucho tiempo sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para una pose nueva de 4 bloques:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Espacio candidato !! Tiempo sin uso !! ¿Sirve?&lt;br /&gt;
|-&lt;br /&gt;
| Pose A: 2 bloques, sin espacio contiguo utilizable || 20 || No: solo deja 2 bloques.&lt;br /&gt;
|-&lt;br /&gt;
| Pose B: 4 bloques || 8 || Sí: puede alojar la pose nueva.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
En este caso se puede reemplazar B y conservar A. A lleva más tiempo sin uso, pero su espacio no permite atender la solicitud.&lt;br /&gt;
&lt;br /&gt;
Si dos o más regiones contiguas pueden reemplazarse, el sistema puede considerarlas juntas. Para esa combinación:&lt;br /&gt;
&lt;br /&gt;
* Suma sus cantidades de bloques.&lt;br /&gt;
* Utiliza la &#039;&#039;&#039;menor puntuación&#039;&#039;&#039; de las regiones combinadas, es decir, el menor tiempo sin uso.&lt;br /&gt;
* Si una está restringida o protegida, no puede utilizarla para completar el espacio.&lt;br /&gt;
&lt;br /&gt;
Así una pose usada recientemente no puede quedar sobrescrita por combinarla con otra que lleva mucho tiempo sin uso.&lt;br /&gt;
&lt;br /&gt;
==== Elegir entre candidatos válidos ====&lt;br /&gt;
&lt;br /&gt;
# El candidato debe tener al menos la cantidad de bloques solicitada.&lt;br /&gt;
# Se prefiere la puntuación más alta: espacio libre o mayor tiempo sin uso.&lt;br /&gt;
# Si las puntuaciones son iguales, se prefiere el candidato con menos bloques, siempre que la pose quepa.&lt;br /&gt;
# Si puntuación y tamaño también coinciden, se conserva el candidato que ya se había elegido.&lt;br /&gt;
&lt;br /&gt;
Las regiones se combinan durante la búsqueda cuando el candidato todavía es demasiado pequeño. No se juntan todas las regiones reemplazables sin tener en cuenta el tamaño solicitado.&lt;br /&gt;
&lt;br /&gt;
=== Reemplazar y dividir la región elegida ===&lt;br /&gt;
&lt;br /&gt;
Una vez elegido el espacio:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemovePosesInSpace&amp;lt;/code&amp;gt; recorre sus regiones y retira de la tabla hash las poses que haya que reemplazar.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemoveSpace&amp;lt;/code&amp;gt; representa el espacio elegido como una región libre, actualizando sus extremos.&lt;br /&gt;
# Se busca una entrada hash libre y se guarda el bloque de comienzo en &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; registra la pose.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_AddPoseInSpace&amp;lt;/code&amp;gt; escribe el índice hash de la pose y el comienzo de su región en el primer y último bloque.&lt;br /&gt;
# Si sobran bloques, crea otra región libre con el resto.&lt;br /&gt;
&lt;br /&gt;
Si una región de 6 bloques aloja una pose de 4, quedan una región ocupada de 4 y una libre de 2. Dynamic Xtreme no tiene un sistema de desfragmentación de VRAM: no desplaza las poses cargadas para reunir los espacios libres.&lt;br /&gt;
&lt;br /&gt;
=== DynamicRoutine: preparar las transferencias de la pose ===&lt;br /&gt;
&lt;br /&gt;
En este punto ya se eligió el espacio y se registró la pose. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; convierte esa asignación en solicitudes de transferencia.&lt;br /&gt;
&lt;br /&gt;
Utiliza estos datos:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Dato !! Cantidad consultada por pose !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Bloque de comienzo || 1 byte || Lugar elegido por el mapa de VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; || 2 bytes de una tabla de 256 bytes || Convierte uno de los 128 bloques en un desplazamiento de VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 bytes || Dirección completa de los datos de la pose en ROM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 bytes: dos valores de 2 || Cantidad de bytes del primer y del segundo tramo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 bytes || Desplazamiento de VRAM para el segundo tramo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Convertir el bloque en una dirección de VRAM ====&lt;br /&gt;
&lt;br /&gt;
Los bloques de 16×16 no se convierten simplemente en un desplazamiento lineal de bytes. Cada uno utiliza tiles de 8×8 distribuidos en las filas de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; contempla esa distribución. Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bloque !! Desplazamiento !! Dirección de VRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas direcciones de VRAM están expresadas en palabras de 2 bytes, no en bytes. La rutina suma la base &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; utilizada para los gráficos de sprites.&lt;br /&gt;
&lt;br /&gt;
==== Procesar los tramos y sus filas ====&lt;br /&gt;
&lt;br /&gt;
# Obtiene el origen desde &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Procesa los bytes del primer tramo mediante &amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si el segundo tramo tiene tamaño 0, termina.&lt;br /&gt;
# Si existe, adelanta el origen la cantidad de bytes del primer tramo.&lt;br /&gt;
# Suma &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; al desplazamiento de VRAM y procesa el segundo tramo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt; divide cada tramo según las filas y el punto de comienzo. Para un destino V expresado en palabras de VRAM, prepara:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Final de la primera fila = (V + $0100) AND $FF00&lt;br /&gt;
Bytes hasta ese final = (final de la primera fila - V) × 2&lt;br /&gt;
Destino de la segunda parte = final de la primera fila + $0100&lt;br /&gt;
Bytes de la segunda parte de un grupo = $0200 - bytes de la primera&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los tamaños son cantidades de bytes, mientras que los destinos de VRAM están expresados en palabras. Por eso se multiplica por 2 al calcular cuántos datos caben hasta el final de una fila.&lt;br /&gt;
&lt;br /&gt;
La rutina utiliza tres recorridos:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt;: añade una solicitud final con los bytes restantes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLinesWithEndLine&amp;lt;/code&amp;gt;: añade dos solicitudes para los datos restantes, cada una con su destino y cantidad de bytes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLines&amp;lt;/code&amp;gt;: añade dos solicitudes que suman &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, avanza el origen y los destinos y repite con los datos que faltan.&lt;br /&gt;
&lt;br /&gt;
Hay un caso directo antes del recorrido general: si el destino comienza en un límite de &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; palabras y el tramo tiene al menos &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, la rutina utiliza &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt; para preparar la copia del tramo completo en una solicitud.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, un tramo de &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes que comienza en &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; se divide así:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Solicitud !! Origen !! Destino VRAM !! Bytes&lt;br /&gt;
|-&lt;br /&gt;
| Primera || Comienzo del tramo || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt;: 448&lt;br /&gt;
|-&lt;br /&gt;
| Segunda || Comienzo del tramo + &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0040&amp;lt;/code&amp;gt;: 64&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las dos solicitudes copian los 512 bytes del tramo, respetando los destinos que calcula la distribución de filas. No son dos copias completas de la pose.&lt;br /&gt;
&lt;br /&gt;
Cada solicitud utiliza estas tablas:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Por cada solicitud añadida aumenta &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
La cantidad total de bytes de la pose ya se comprobó y se añadió a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;. Esta parte divide esa carga en transferencias; no vuelve a contar la pose completa por cada solicitud.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; &#039;&#039;&#039;no ejecuta DMA&#039;&#039;&#039;. Deja las solicitudes preparadas para que &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt; las copie durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== Qué conserva el sprite ===&lt;br /&gt;
&lt;br /&gt;
Las rutinas de sprites guardan el índice hash de la pose utilizable, no una copia independiente de sus gráficos. Ese índice permite consultar su bloque de VRAM y mantener actualizado su tiempo de uso.&lt;br /&gt;
&lt;br /&gt;
Si una pose nueva no puede cargarse:&lt;br /&gt;
&lt;br /&gt;
* Si existe una pose anterior válida, se mantiene y se actualiza su tiempo de uso para protegerla.&lt;br /&gt;
* Si nunca hubo una pose válida, no se debe dibujar como si la solicitud hubiera tenido éxito.&lt;br /&gt;
* En las llamadas con soporte para mantener la anterior, el carry puede indicar que todavía hay una pose utilizable aunque no se haya completado el cambio.&lt;br /&gt;
&lt;br /&gt;
La animación y el movimiento siguen siendo responsabilidad del sprite. La caché se ocupa de reutilizar o preparar los gráficos solicitados.&lt;br /&gt;
&lt;br /&gt;
=== Ejemplo: dos sprites solicitan la misma pose ===&lt;br /&gt;
&lt;br /&gt;
Supongamos que dos sprites visibles, A y B, necesitan la pose dinámica &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt;. Sus paletas ya están listas, la pose todavía no está en VRAM y hay espacio y presupuesto para cargarla.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;El sprite A solicita la pose.&#039;&#039;&#039; La búsqueda no encuentra &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; en la caché. El sistema elige un espacio, registra la pose y prepara las transferencias de sus gráficos. A guarda el índice de esa entrada en &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;. Los gráficos aún no se han copiado a VRAM.&lt;br /&gt;
# &#039;&#039;&#039;A prepara su dibujo.&#039;&#039;&#039; La rutina de dibujo utiliza la entrada registrada para calcular los tiles que corresponden a ese espacio de VRAM y escribe sus posiciones y propiedades en los buffers OAM.&lt;br /&gt;
# &#039;&#039;&#039;El sprite B solicita la misma pose.&#039;&#039;&#039; La búsqueda ya encuentra &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; registrada, aunque su transferencia siga pendiente. Actualiza su tiempo de último uso y no programa otra carga. B guarda el mismo índice de caché en su propia &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &#039;&#039;&#039;B prepara su dibujo.&#039;&#039;&#039; Escribe sus propias piezas en los buffers OAM, utilizando los mismos gráficos que A, pero con su posición, paleta y volteo.&lt;br /&gt;
# &#039;&#039;&#039;Durante NMI se actualizan los datos de video.&#039;&#039;&#039; Se realizan las transferencias pendientes de la pose a VRAM y el juego transfiere los buffers OAM. En la siguiente imagen, los dos sprites utilizan los mismos gráficos cargados.&lt;br /&gt;
&lt;br /&gt;
Se prepara una sola carga de la pose, aunque dos sprites la utilicen. Esa carga puede necesitar varias transferencias DMA según cómo se distribuyan sus gráficos en VRAM.&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, que la pose esté &#039;&#039;&#039;disponible&#039;&#039;&#039; durante la lógica significa que ya tiene una entrada y un espacio asignados, con su carga preparada para NMI. Si sus gráficos ya estaban en VRAM, se reutilizan directamente y no hay que preparar otra transferencia.&lt;br /&gt;
&lt;br /&gt;
Si la solicitud de A fuera rechazada, no se registraría la pose nueva ni quedaría su carga pendiente. A utilizaría su pose anterior si tiene una; de lo contrario, no dispondría de una pose para dibujar. B tendría que resolver su propia solicitud y no encontraría una entrada creada por el intento rechazado de A.&lt;br /&gt;
&lt;br /&gt;
== Efectos de paleta: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
El sistema conserva los colores originales para poder cambiar de efecto, combinarlo con otro o volver a la paleta sin efecto. No debe utilizar el resultado ya afectado como si fuera la paleta original.&lt;br /&gt;
&lt;br /&gt;
=== Buffers de colores ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o buffer !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 || 2 por color || Colores de base en formato SNES, con 2 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 || 3 por color || Base separada en rojo, verde y azul, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 || 3 por color || Base separada en tono, saturación y luminosidad, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 || 2 por color || Resultado en formato SNES, listo para solicitar su copia a CGRAM. Corresponde al buffer de paletas del juego.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Indicadores de cada paleta ===&lt;br /&gt;
&lt;br /&gt;
Cada bit de estos indicadores corresponde a una paleta. Las variables &amp;lt;code&amp;gt;BG&amp;lt;/code&amp;gt; cubren 0-7 y las &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt; cubren 8-F.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variables !! Bytes totales !! Bytes por valor !! Qué indican&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si ya se preparó la base de colores en formato SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparada la conversión de la base a RGB.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparada la conversión de la base a HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparado el resultado del efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos indicadores evitan repetir conversiones y cálculos que siguen siendo válidos.&lt;br /&gt;
&lt;br /&gt;
=== Preparar una base ===&lt;br /&gt;
&lt;br /&gt;
# Se comprueba si la paleta ya tiene una base registrada.&lt;br /&gt;
# Si no la tiene, se obtienen los colores del buffer del juego. Una carga explícita, como &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, puede proporcionar esa base directamente.&lt;br /&gt;
# Se comprueba si el efecto necesita RGB o HSL.&lt;br /&gt;
# Si falta esa conversión, se prepara y se marca como disponible.&lt;br /&gt;
&lt;br /&gt;
Si solo cambia el efecto, la base puede seguir siendo válida. Si cambian los colores originales, las llamadas de carga actualizan la base e invalidan las conversiones y resultados que deben calcularse otra vez.&lt;br /&gt;
&lt;br /&gt;
=== Datos de un efecto ===&lt;br /&gt;
&lt;br /&gt;
El ID permite consultar las tablas generadas durante la instalación:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt;: cálculo que debe realizarse.&lt;br /&gt;
* &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt;: valores de los canales o dirección de la paleta de destino de una transición.&lt;br /&gt;
* &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt;: cuánto se aplica cada cambio.&lt;br /&gt;
&lt;br /&gt;
Los canales utilizan valores de 0 a 31. Los ratios van de 0 a 127: 0 conserva el origen y 127 aplica por completo el cambio elegido.&lt;br /&gt;
&lt;br /&gt;
Los cálculos se realizan fuera de NMI. NMI realiza la transferencia de los colores resultantes.&lt;br /&gt;
&lt;br /&gt;
=== Efecto global ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Bytes totales !! Bytes por valor !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 || 2 || Selecciona el efecto global. El valor 0 permite restaurar los colores de base.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta || Selecciona las paletas 0-7 que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta || Selecciona las paletas 8-F que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 32 || 2 || Guarda el último ID global procesado por cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 || 1 || Controla la participación del color fijo y el color 0,0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para cada paleta habilitada, el administrador:&lt;br /&gt;
&lt;br /&gt;
# Comprueba si necesita actualizar el resultado del efecto.&lt;br /&gt;
# Prepara la base RGB o HSL si todavía falta.&lt;br /&gt;
# Calcula el efecto si el resultado anterior ya no sirve.&lt;br /&gt;
# Prepara los colores en formato SNES y solicita su transferencia.&lt;br /&gt;
# Confirma el ID procesado cuando la carga correspondiente se acepta.&lt;br /&gt;
&lt;br /&gt;
Si se mantiene el mismo efecto y no cambió la base, no hace falta calcularlo otra vez. Al cambiar el ID global se invalidan los resultados anteriores, no necesariamente las bases RGB y HSL.&lt;br /&gt;
&lt;br /&gt;
El ID global 0 también requiere una actualización: el sistema debe cargar de nuevo los colores de base para quitar el efecto anterior.&lt;br /&gt;
&lt;br /&gt;
=== Efecto local y concatenación ===&lt;br /&gt;
&lt;br /&gt;
Un recurso puede tener un efecto propio y recibir también el global. Por ejemplo, un sprite puede cambiar de tono y después oscurecerse junto con el nivel.&lt;br /&gt;
&lt;br /&gt;
El orden es:&lt;br /&gt;
&lt;br /&gt;
# Preparar el resultado del efecto local.&lt;br /&gt;
# Utilizarlo como base para el efecto global mediante la llamada de concatenación.&lt;br /&gt;
# Calcular el efecto global sobre esa base.&lt;br /&gt;
# Cargar el resultado combinado, sin mostrar antes la versión que solo tiene el efecto local.&lt;br /&gt;
&lt;br /&gt;
* La concatenación RGB se utiliza con efectos RGB.&lt;br /&gt;
* La concatenación HSL se utiliza con efectos HSL.&lt;br /&gt;
* Los recursos que comparten un destino de CGRAM comparten sus colores. Para mostrar dos efectos locales distintos, necesitan destinos que permitan mantener ambos resultados.&lt;br /&gt;
&lt;br /&gt;
=== Si no se acepta la transferencia ===&lt;br /&gt;
&lt;br /&gt;
* Calcular el efecto no significa que ya esté en CGRAM.&lt;br /&gt;
* Si la transferencia no se acepta, el administrador puede volver a intentar la actualización.&lt;br /&gt;
* Cuando corresponde, se mantiene el resultado anterior utilizable hasta poder sustituirlo.&lt;br /&gt;
* No se deben cargar primero los colores originales sin efecto: podrían verse así durante un frame antes del resultado correcto.&lt;br /&gt;
&lt;br /&gt;
== Cómo trabajan juntos ==&lt;br /&gt;
&lt;br /&gt;
El recorrido de un sprite dinámico reúne estas tareas:&lt;br /&gt;
&lt;br /&gt;
# Su lógica elige la pose y la versión de paleta.&lt;br /&gt;
# La asignación busca una paleta utilizable y prepara los colores si hace falta.&lt;br /&gt;
# La caché protege la pose ya cargada o prepara la carga de una nueva.&lt;br /&gt;
# El dibujo escribe los datos de sus piezas en los buffers OAM.&lt;br /&gt;
# El administrador de efectos prepara los cambios globales pendientes.&lt;br /&gt;
# NMI realiza las transferencias de gráficos y colores solicitadas.&lt;br /&gt;
&lt;br /&gt;
Compartir gráficos, compartir una paleta y compartir una rutina de dibujo son tres cosas distintas. Dynamic Xtreme puede aprovechar cada una sin obligar a que los recursos compartan también las demás.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_internal_workings&amp;diff=21398</id>
		<title>Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_internal_workings&amp;diff=21398"/>
		<updated>2026-10-25T21:58:02Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: Created page with &amp;quot;{{Select Language|Dynamic_Xtreme_internal_workings}}  This article explains how Dynamic Xtreme works, from preparing resources during installation to loading and drawing a pose during gameplay.  == What installation prepares ==  Before a sprite can use its graphics or palette, Dynamic Xtreme must store them in the ROM and prepare the information needed to find them. The same applies to any other dynamic resource you add.  The tool reads DynamicInfo, DrawInfo, and Palette...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
This article explains how Dynamic Xtreme works, from preparing resources during installation to loading and drawing a pose during gameplay.&lt;br /&gt;
&lt;br /&gt;
== What installation prepares ==&lt;br /&gt;
&lt;br /&gt;
Before a sprite can use its graphics or palette, Dynamic Xtreme must store them in the ROM and prepare the information needed to find them. The same applies to any other dynamic resource you add.&lt;br /&gt;
&lt;br /&gt;
The tool reads DynamicInfo, DrawInfo, and PaletteEffect files. Each provides a different part: which resources to load, how to draw poses, and which color changes can be applied.&lt;br /&gt;
&lt;br /&gt;
This generates defines in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; that make it easy to use the resources and call the required routines.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: resources and upload data ===&lt;br /&gt;
&lt;br /&gt;
A DynamicInfo brings together the pose graphics, palettes, and general resources needed by a sprite or other code. For dynamic pose graphics, the tool arranges the data in the tile layout expected by the system.&lt;br /&gt;
&lt;br /&gt;
Several properties of each pose are stored in separate tables. All tables use the same order: a pose&#039;s entry in one table corresponds to the same pose in the others. In the table below, &#039;&#039;&#039;N&#039;&#039;&#039; is the number of installed dynamic poses.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Total bytes !! Bytes per value !! Contents and purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || 2 × N || 2 || Amount of data used by each pose, in bytes. Used to check whether its upload fits within the frame&#039;s budget.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || N || 1 || Number of 16×16 blocks to allocate in VRAM for the pose. This does not always match the exact byte count copied, since an incomplete tile can still require a block of space.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 × N || 3 || ROM address of each pose&#039;s graphics, including the bank, so upload code can locate the full source address.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 × N || 2; two values per pose || Two sizes per pose, corresponding to the two sections its graphics may be split into. The upload routine uses them to place the data correctly in VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 × N || 2 || VRAM offset from the start of the first section to the start of the second. Places the second section correctly even if the first ends with an incomplete row.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These tables describe every installed pose, not just those on screen. The cache separately tracks which poses are loaded and where they are stored.&lt;br /&gt;
&lt;br /&gt;
For example, when a requested pose is not yet in VRAM, the system checks how many bytes it needs to upload, finds space for its blocks, then uses its source address and section data to prepare the upload.&lt;br /&gt;
&lt;br /&gt;
==== Palette tables ====&lt;br /&gt;
&lt;br /&gt;
Palettes declared in DynamicInfo files are collected in &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. If &#039;&#039;&#039;P&#039;&#039;&#039; is the number of entries across the DynamicInfo palette lists:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; || 2 × P || 2 || ID of each palette.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; || 3 × P || 3 || ROM address of its colors.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
P counts list entries, not just unique palettes: a shared palette may appear in more than one DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
Both lists follow the DynamicInfo palette order. Each DynamicInfo&#039;s offset define identifies where its list starts. Selecting a version adds that index to the offset to find both the ID and address of the chosen colors.&lt;br /&gt;
&lt;br /&gt;
The ID identifies a palette so it can be shared; the address allows its colors to be loaded. Neither is the destination palette number: the same installed palette may be assigned to palette 9 or C, for example.&lt;br /&gt;
&lt;br /&gt;
==== General resources and defines ====&lt;br /&gt;
&lt;br /&gt;
Files declared in &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; are stored in ROM. Their address and byte count are available through defines generated in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. For example, &amp;lt;code&amp;gt;my_resource.bin&amp;lt;/code&amp;gt; generates:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt;: resource address in ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt;: resource byte count.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt;: resource ID.&lt;br /&gt;
&lt;br /&gt;
Names are normalized to PascalCase: spaces, hyphens, and underscores are removed, and each word starts with a capital letter.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: drawing data and routines ===&lt;br /&gt;
&lt;br /&gt;
The DrawInfo describes how a pose is built: its tiles, each tile&#039;s position and size, and how the pose changes when flipped.&lt;br /&gt;
&lt;br /&gt;
During installation, Dynamic Xtreme generates drawing routines optimized for the parameters used by the tiles. For example, it considers whether tiles need X and Y offsets, share a size or common properties, and require flipping.&lt;br /&gt;
&lt;br /&gt;
The resulting routine only handles options that the drawing needs. Several poses can share a routine when they need the same handling; this does not mean they also share graphics or IDs.&lt;br /&gt;
&lt;br /&gt;
These tables connect a pose to its drawing data. &#039;&#039;&#039;D&#039;&#039;&#039; is the number of drawing poses, and &#039;&#039;&#039;R&#039;&#039;&#039; is the number of generated routines:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Total bytes !! Bytes per value !! Contents and purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || 2 × D || 2 || Starting offset of the pose&#039;s data in its drawing routine&#039;s tables. Locates its tiles and offsets without scanning earlier poses.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || D || 1 || Number of tiles in the pose minus one. A four-tile pose stores 3; the routine uses this to loop through its tiles.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || D || 1 || Drawing routine used by each pose. Poses with compatible requirements can use the same routine ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || 3 × R || 3 per routine || Drawing routine addresses. The routine ID selects the code to run.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each routine also has the tables its poses need. Here, &#039;&#039;&#039;T&#039;&#039;&#039; is the number of entries in each of the routine&#039;s tables:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Data !! Total bytes !! Bytes per value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || T, if generated || 1 || Tile numbers making up the pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || T, if generated || 1 || Each tile&#039;s properties, such as flipping and priority relative to the layers.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || T per table, if generated || 1 || Each tile&#039;s position relative to the pose&#039;s origin.&lt;br /&gt;
|-&lt;br /&gt;
| Flip displacement tables || T per table, if generated || 1 || Positions used when flipping a pose that requires a different layout.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || T, if generated || 1 || Each tile&#039;s size: 8×8 or 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Not every routine needs all these tables. If a value is the same for all tiles or can be obtained from a shared value, the tool can generate a routine that uses it directly.&lt;br /&gt;
&lt;br /&gt;
This optimization happens during installation. For example, when all tiles share a size, the routine can use that common value instead of reading a separate size for each tile.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: effect data ===&lt;br /&gt;
&lt;br /&gt;
A PaletteEffect file contains a list of color changes. Installation assigns IDs to them and stores their data in &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
As with pose tables, each effect occupies the same position across the different lists. Effect IDs start at 1; ID 0 means no global effect. In the table, &#039;&#039;&#039;E&#039;&#039;&#039; is the number of installed effects; together, the tables occupy &#039;&#039;&#039;2 + 7 × E bytes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table section !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || 2 || 2 || Number of installed effects.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || E || 1 || Each effect&#039;s type, such as &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Selects the calculation to perform.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || E per table; 3 × E combined || 1 per table || Channel values used by the effect. For transitions, these three bytes store the target palette address instead.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || E per table; 3 × E combined || 1 per table || How much of the change to apply to each component. Range: 0–127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For a transition toward another palette, the tool also prepares that palette. It converts the colors to the RGB or HSL format needed by the transition and stores them in ROM. During gameplay, this target can be used without converting it again on every call.&lt;br /&gt;
&lt;br /&gt;
These transition palettes differ from normal palettes uploaded to CGRAM: they contain three components per color and are used to calculate effects.&lt;br /&gt;
&lt;br /&gt;
=== How code finds installed resources ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; provides the IDs, addresses, sizes, and offsets resources need. For example, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifies a pose, and &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifies a file&#039;s first effect.&lt;br /&gt;
&lt;br /&gt;
Names are normalized to PascalCase: separators such as spaces, hyphens, and underscores are removed, and each word starts with a capital letter. For example, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Installation also generates &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, which stores the addresses of the blocks containing inserted resources. Each address occupies 3 bytes, followed by a final &amp;lt;code&amp;gt;$FFFFFF&amp;lt;/code&amp;gt; value occupying another 3 bytes. For B blocks, the table occupies &amp;lt;code&amp;gt;3 × (B + 1)&amp;lt;/code&amp;gt; bytes. The tool uses this information to find the previous installation&#039;s data when reinstalling.&lt;br /&gt;
&lt;br /&gt;
Reinstallation may change IDs and addresses. Reinsert any sprites, blocks, and UberASM code that use the generated defines afterward.&lt;br /&gt;
&lt;br /&gt;
== Work performed each frame ==&lt;br /&gt;
&lt;br /&gt;
The main game logic runs the player, sprites, and other code for the current game mode. Code using Dynamic Xtreme requests poses and palettes, prepares local effects, and calls drawing routines. Accepted uploads are added to the transfer lists for NMI.&lt;br /&gt;
&lt;br /&gt;
Once that logic finishes, Dynamic Xtreme&#039;s game mode code performs the tasks enabled by the configuration: preparing VRAM updates for Kevin&#039;s optimization, maintaining palette state, and calculating pending global effects.&lt;br /&gt;
&lt;br /&gt;
During NMI, Dynamic Xtreme then performs these tasks in order, according to the enabled features:&lt;br /&gt;
&lt;br /&gt;
# Resets &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; to 0.&lt;br /&gt;
# Increments &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Increments &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; if the action is not frozen and the game is not paused.&lt;br /&gt;
# Performs graphics transfers to VRAM.&lt;br /&gt;
# Performs color transfers to CGRAM.&lt;br /&gt;
# Updates color 0,0 if the effect system has a pending result.&lt;br /&gt;
&lt;br /&gt;
The following sections therefore follow this order: &#039;&#039;&#039;main logic → tasks at the end of the game mode → NMI transfers&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Main logic ===&lt;br /&gt;
&lt;br /&gt;
Each resource decides what it needs. A sprite may change pose, an animation may request new graphics, or UberASM code may upload a palette or select an effect.&lt;br /&gt;
&lt;br /&gt;
If the requested pose is already loaded, Dynamic Xtreme updates its last-use time to protect it from replacement without uploading its graphics again. Otherwise, it checks the frame&#039;s data budget and finds available VRAM space before preparing the upload.&lt;br /&gt;
&lt;br /&gt;
Drawing is also prepared here: routines write the positions, tiles, and properties of the pieces to display into the OAM buffers.&lt;br /&gt;
&lt;br /&gt;
A request can fail, for example because its data would exceed the remaining budget. The requesting code must check the result and decide whether to keep the previous state or retry later. A rejected upload is not automatically saved for another frame.&lt;br /&gt;
&lt;br /&gt;
=== Game mode tasks ===&lt;br /&gt;
&lt;br /&gt;
This stage performs the following tasks, according to the enabled features.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Before game logic runs:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# If &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt; is enabled, the controller routine runs here instead of during NMI.&lt;br /&gt;
# Checks whether Dynamic Xtreme should run in the current game mode. If not, its variables are reset. This happens every frame spent in a disallowed mode.&lt;br /&gt;
&lt;br /&gt;
The normal game logic then runs, including sprites and code requesting uploads or palette changes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;After that logic finishes:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# If Kevin&#039;s VRAM optimization is enabled, Lunar Magic&#039;s update destinations are adjusted before the transfers take place.&lt;br /&gt;
# Palette update flags are cleared to 0, and protection timers greater than 0 are decremented. This is skipped while paused and in disallowed modes.&lt;br /&gt;
# Applies global effects to palettes that need an update and prepares their color transfers. This is also skipped if the previous check prevents further processing.&lt;br /&gt;
&lt;br /&gt;
VRAM and CGRAM transfers happen later, during NMI. This stage prepares what will be copied.&lt;br /&gt;
&lt;br /&gt;
=== Allowed game modes ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme uses two game mode checks:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;General system:&#039;&#039;&#039; &amp;lt;code&amp;gt;Routines_AllowedGameMode&amp;lt;/code&amp;gt;, exposed as &amp;lt;code&amp;gt;!AllowedGameMode&amp;lt;/code&amp;gt;. Determines whether the system is reset, its NMI runs, and palette tasks are performed. Palette assignment macros also use this check when processing an upload from a DynamicInfo.&lt;br /&gt;
* &#039;&#039;&#039;Sprite routines:&#039;&#039;&#039; &amp;lt;code&amp;gt;DXAllowedGameMode&amp;lt;/code&amp;gt; uses a separate table. &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; and its general macros use a table with the same values to decide whether to process a new request.&lt;br /&gt;
&lt;br /&gt;
Enabling the general system therefore does not mean every sprite function accepts new uploads in that mode. This table shows the current checks; IDs are hexadecimal:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Game mode !! SMW screen or stage !! General system !! DXAllowedGameMode / new Upload requests&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt; || Title screen spotlight opening. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || Title screen. || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || File select. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$09&amp;lt;/code&amp;gt; || File erase. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt; || One- or two-player selection. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; || Overworld loading. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0D&amp;lt;/code&amp;gt; || Overworld fade-in. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; || Overworld. || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt; || Level preparation. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$13&amp;lt;/code&amp;gt; || Level fade-in. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || In-level gameplay. || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$15&amp;lt;/code&amp;gt; || Fade-out to Game Over / Time Up. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; || Castle cutscene or credits. || No || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt; || Fade-out to Yoshi&#039;s House in the credits. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1D&amp;lt;/code&amp;gt; || Loading Yoshi&#039;s House in the credits. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt; || Yoshi&#039;s House fade-in during the credits. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1F&amp;lt;/code&amp;gt; || Yoshi&#039;s House in the credits. || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$24&amp;lt;/code&amp;gt; || Enemy roll fade-in. || Yes || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt; || Credits enemy roll. || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$29&amp;lt;/code&amp;gt; || The End screen. || No || Yes&lt;br /&gt;
|-&lt;br /&gt;
| Other values from &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$2F&amp;lt;/code&amp;gt;. || — || No || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Stage names follow the [https://github.com/IsoFrieze/SMWDisX/blob/master/bank_00.asm SMW game modes documented in SMWDisX]; permissions come from Dynamic Xtreme&#039;s tables.&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Upload&amp;lt;/code&amp;gt; does not allow a new request, it checks whether the resource has a previous pose. If so, it updates that pose&#039;s last-use time and returns carry set; otherwise, it returns carry clear. It does not request another pose on this path.&lt;br /&gt;
&lt;br /&gt;
Modes &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$29&amp;lt;/code&amp;gt; show why the columns must be read separately: passing the sprite check does not enable the general system&#039;s NMI or prevent the game mode code from resetting its variables. The sprite column alone does not guarantee full operation in those modes.&lt;br /&gt;
&lt;br /&gt;
=== Transfers during NMI ===&lt;br /&gt;
&lt;br /&gt;
NMI is an interrupt the SNES can generate at the start of VBlank, after drawing the visible part of the screen. The game uses this interval to update graphics, colors, and other video data.&lt;br /&gt;
&lt;br /&gt;
In allowed modes, Dynamic Xtreme performs these tasks in order, according to the enabled features:&lt;br /&gt;
&lt;br /&gt;
# Resets &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; to 0 to count requests from the next logic cycle. Transfers already prepared remain in their lists.&lt;br /&gt;
# Increments &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Checks &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt;. If both are 0, increments &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Performs pending VRAM transfers if &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; is enabled.&lt;br /&gt;
# Performs pending CGRAM transfers if &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; is enabled.&lt;br /&gt;
# If &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; is enabled, updates color 0,0 when a result is pending.&lt;br /&gt;
&lt;br /&gt;
The copies use DMA. NMI reads each request from the lists, sets the source address, byte count, and destination, then starts the transfer.&lt;br /&gt;
&lt;br /&gt;
VBlank time is limited, and SMW also needs it for its own screen updates. To limit data sent in one frame and prevent flickering, Dynamic Xtreme uses &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; to count requested bytes and &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; to set the limit. Before accepting a normal upload, it checks whether the additional bytes would exceed that limit.&lt;br /&gt;
&lt;br /&gt;
==== Transfer lists ====&lt;br /&gt;
&lt;br /&gt;
Each request stores the source address and bank, byte count, and VRAM or CGRAM destination.&lt;br /&gt;
&lt;br /&gt;
NMI processes the lists from the last entry to the first, then empties them. This does not erase the uploaded graphics or colors: they stay at their destinations until other code changes them.&lt;br /&gt;
&lt;br /&gt;
The VRAM list uses 0 when empty. The CGRAM list uses &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; because it stores the last entry&#039;s index rather than the entry count directly.&lt;br /&gt;
&lt;br /&gt;
Code writing to the same destination must coordinate its uploads. Request order does not replace deciding which resource may use each region.&lt;br /&gt;
&lt;br /&gt;
Resources are normally read from ROM. If a resource is in a RAM buffer, you must keep its contents unchanged until NMI performs the transfer. For example, a palette prepared in RAM must not be modified or its buffer reused before the copy. The list stores the address, not a copy of the data; Dynamic Xtreme does not protect the buffer from changes made by other code.&lt;br /&gt;
&lt;br /&gt;
==== Data budget ====&lt;br /&gt;
&lt;br /&gt;
Transfer macros such as &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt; check the requested byte count in &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;. If the new upload would exceed &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, it is rejected. Accepted uploads add their bytes to the counter.&lt;br /&gt;
&lt;br /&gt;
The default limit is &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, or 2048 bytes. It helps prevent flickering caused by sending too much data in a frame. It limits data volume, rather than measuring the exact time each transfer takes.&lt;br /&gt;
&lt;br /&gt;
Variants such as &amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;%ForcedTransferToCGRAM()&amp;lt;/code&amp;gt; accept uploads without checking the limit. Their bytes still count toward &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, leaving less room for later normal uploads. They are used for priority uploads, such as the player&#039;s graphics; they do not prevent flickering if too much data is requested.&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme_ASM_API#PPU|PPU in the ASM API]] for the difference between byte budget and list capacity, transfer restrictions, and the checks your code must perform.&lt;br /&gt;
&lt;br /&gt;
==== The two timers ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_Timer: protecting requests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; advances when Dynamic Xtreme&#039;s NMI code runs. Besides measuring how long a pose has gone unused, it prevents a resource from repeating requests before its previous ones have been processed.&lt;br /&gt;
&lt;br /&gt;
A logic cycle does not always correspond to a full NMI execution. During slowdown, SMW may run a shortened NMI, allowing two logic cycles to occur without Dynamic Xtreme&#039;s transfer lists being processed between them.&lt;br /&gt;
&lt;br /&gt;
Without protection, a resource could add its uploads to those lists again. Duplicate requests would take more space and could cause flickering.&lt;br /&gt;
&lt;br /&gt;
To prevent this, sprite pose upload routines compare &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; with a two-byte value stored by the sprite, usually called &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt;. The sprite aliases use &amp;lt;code&amp;gt;!SafeFrameLowByte,x&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!SafeFrameHighByte,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The process is:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Compare the timers.&#039;&#039;&#039; If &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; equals &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;, that sprite has already processed its pose upload at this timer value. The routine skips a new request.&lt;br /&gt;
# &#039;&#039;&#039;Record the attempt before processing it.&#039;&#039;&#039; If the values differ, it copies &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt;, then checks whether it can reuse the pose or must request another.&lt;br /&gt;
# &#039;&#039;&#039;Check the result.&#039;&#039;&#039; A new pose request can succeed or fail. Even if it fails, the value saved in &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; is not undone.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; therefore records &#039;&#039;&#039;when the last attempt was processed&#039;&#039;&#039;, not when a pose was successfully loaded. If an upload fails, calling the routine again with the same &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; does not allow another attempt, even if the desired pose or available space has changed.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;, rejected requests and calls skipped by this protection use the same fallback:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; is not &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, they update that pose&#039;s last-use time to protect it from replacement and return carry set. The sprite can keep drawing the last available pose.&lt;br /&gt;
* If it is &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no fallback pose exists and they return carry clear.&lt;br /&gt;
&lt;br /&gt;
For example, this can happen during slowdown:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;DX_Timer = $0030&amp;lt;/code&amp;gt;. The sprite saves &amp;lt;code&amp;gt;$0030&amp;lt;/code&amp;gt; in its &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; and tries to obtain a new pose. No data budget remains, so the request fails; it keeps the previous pose if one exists.&lt;br /&gt;
# SMW runs another logic cycle without processing Dynamic Xtreme&#039;s NMI. The timer is still &amp;lt;code&amp;gt;$0030&amp;lt;/code&amp;gt;. The same sprite&#039;s next call detects the match and does not repeat the request.&lt;br /&gt;
# When Dynamic Xtreme&#039;s NMI runs, &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; advances to &amp;lt;code&amp;gt;$0031&amp;lt;/code&amp;gt;. On the next call, the timers no longer match and the sprite can retry. A rejected request does not retry itself: the sprite code must call the routine again.&lt;br /&gt;
&lt;br /&gt;
Sprite pose upload aliases enable this protection. In [[Dynamic_Xtreme_ASM_API#GeneralUpload|GeneralUpload]] and [[Dynamic_Xtreme_ASM_API#Upload_(general_macro)|Upload (general macro)]], &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; controls it; &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; separately controls fallback to the previous pose. [[Dynamic_Xtreme_ASM_API#TakeDynamicRequest|TakeDynamicRequest]] and [[Dynamic_Xtreme_ASM_API#PPU|PPU transfer macros]] do not perform this &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; check for you.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; continues advancing while paused whenever this part of NMI runs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_SyncTimer: synchronized animations&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The main purpose of &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; is to give sprites a shared animation clock. For example, sprites using the same poses can use it to select a pose every four frames.&lt;br /&gt;
&lt;br /&gt;
They then change together and request the same pose. The first request may need to upload it; later requests reuse it without scheduling another graphics upload. This saves DMA transfers and data per frame.&lt;br /&gt;
&lt;br /&gt;
With independent timers, sprites could use different poses from the same animation at once, requiring more uploads and VRAM space.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; stops while paused or while the action is frozen, so synchronized animations stop too.&lt;br /&gt;
&lt;br /&gt;
== Graphics uploads: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; stores a list of upload requests in RAM. During NMI, those requests are processed and their data is copied to VRAM.&lt;br /&gt;
&lt;br /&gt;
=== List variables ===&lt;br /&gt;
&lt;br /&gt;
Here, &#039;&#039;&#039;V&#039;&#039;&#039; is &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt;, which defaults to 64. Each of the four request tables allocates V bytes; with 2-byte entries, that allows 32 requests. Together with the counter, they occupy &amp;lt;code&amp;gt;1 + 4 × V&amp;lt;/code&amp;gt; bytes: 257 by default.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable or table !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Number of pending requests. 0 means the list is empty.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || V; 64 by default || 2 || Each request&#039;s source address, excluding the bank.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || V; 64 by default || 2 allocated; 1-byte bank || Source bank.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || V; 64 by default || 2 || Number of bytes to copy.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || V; 64 by default || 2 || VRAM destination address.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Tables use the same order: the first entry of each table belongs to the first request, the second to the second request, and so on. Each entry occupies 2 bytes, so offsets advance through &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt;, and so on.&lt;br /&gt;
&lt;br /&gt;
These names represent RAM addresses calculated in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Addresses can change with the configuration and enabled features.&lt;br /&gt;
&lt;br /&gt;
=== Adding a request ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; performs these steps:&lt;br /&gt;
&lt;br /&gt;
# Calculates the total byte count if the new upload is added to &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Compares it with &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;. If it exceeds the limit, returns carry clear without adding the request.&lt;br /&gt;
# Uses &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; to find the next entry and increments that counter.&lt;br /&gt;
# Stores the source, bank, byte count, and destination in the tables.&lt;br /&gt;
# Updates &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; with the upload&#039;s byte count and returns carry set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; stores the same information without checking the byte limit. &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; variants make it easier to get the source from a full address or resource defines.&lt;br /&gt;
&lt;br /&gt;
Adding a request does not copy graphics immediately: it prepares the information for NMI.&lt;br /&gt;
&lt;br /&gt;
=== Processing requests during NMI ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt; routine:&lt;br /&gt;
&lt;br /&gt;
# Reads &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;. If it is 0, returns because there are no requests.&lt;br /&gt;
# Calculates the last entry&#039;s offset: &amp;lt;code&amp;gt;(Length - 1) × 2&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reads its source, bank, and byte count into the DMA registers.&lt;br /&gt;
# Writes the VRAM destination to &amp;lt;code&amp;gt;$2116-$2117&amp;lt;/code&amp;gt; and starts the transfer through &amp;lt;code&amp;gt;$420B&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Moves back 2 bytes to process the previous request, repeating until the first is complete.&lt;br /&gt;
# Writes 0 to &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; to mark the list as empty.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The list runs from last to first.&#039;&#039;&#039; There is no need to clear every stored value afterward: with the length at 0, the next request reuses the first entry.&lt;br /&gt;
&lt;br /&gt;
=== Animations with a fixed destination ===&lt;br /&gt;
&lt;br /&gt;
Animation code must:&lt;br /&gt;
&lt;br /&gt;
# Select the image for the current animation step.&lt;br /&gt;
# Calculate its source address.&lt;br /&gt;
# Request a transfer to the animation&#039;s VRAM destination.&lt;br /&gt;
# Check carry. If the upload is rejected, keep the previous image and retry.&lt;br /&gt;
&lt;br /&gt;
The destination can stay the same. Only the image copied there changes; the transfer list does not decide when the animation advances.&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme_UberASM_guide#Creating_graphics_animations|Creating graphics animations in the UberASM guide]] for complete code.&lt;br /&gt;
&lt;br /&gt;
=== Loading a dynamic pose ===&lt;br /&gt;
&lt;br /&gt;
Pose loading uses the cache to avoid uploading graphics that are already available:&lt;br /&gt;
&lt;br /&gt;
# Looks for the ID in the hash table.&lt;br /&gt;
# If already registered, updates its last-use time without adding another upload.&lt;br /&gt;
# Otherwise, checks the byte count and finds suitable space in the VRAM map.&lt;br /&gt;
# Selects poses that can be replaced, considering their time since last use and the new pose&#039;s space requirements.&lt;br /&gt;
# Updates the cache tables and map.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; splits the pose&#039;s data into the required transfers.&lt;br /&gt;
# NMI performs those transfers.&lt;br /&gt;
&lt;br /&gt;
[[#Dynamic_sprites:_DynamicPoses|Dynamic sprites: DynamicPoses]] covers each step, including hash lookup, the map, replacement policy, and splitting uploads into rows.&lt;br /&gt;
&lt;br /&gt;
== Palette uploads and assignment: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
The system distinguishes two values:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Palette ID:&#039;&#039;&#039; identifies colors stored in ROM.&lt;br /&gt;
* &#039;&#039;&#039;Destination color:&#039;&#039;&#039; specifies the starting color in CGRAM for the uploaded colors. For example, &amp;lt;code&amp;gt;$91&amp;lt;/code&amp;gt; starts at color 1 of palette 9.&lt;br /&gt;
&lt;br /&gt;
Automatic assignment lets sprites share colors without requiring a fixed destination for each sprite.&lt;br /&gt;
&lt;br /&gt;
=== CGRAM upload list ===&lt;br /&gt;
&lt;br /&gt;
Here, &#039;&#039;&#039;C&#039;&#039;&#039; is &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt;, which defaults to 64. The tables and counter allocate &amp;lt;code&amp;gt;1 + 7 × C&amp;lt;/code&amp;gt; bytes, or 449 by default. Although &amp;lt;code&amp;gt;SourceBNK&amp;lt;/code&amp;gt; allocates 2 × C bytes, the code uses one bank byte per request.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable or table !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Last pending request&#039;s index. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; means the list is empty; 0 means one request.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || 2 × C; 128 by default || 2 || Source address, excluding the bank.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || 2 × C; 128 allocated by default || 1 used per request || Source bank.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || 2 × C; 128 by default || 2 || Number of bytes to copy. Each color occupies 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || C; 64 by default || 1 || First destination color in CGRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
During NMI, &amp;lt;code&amp;gt;CGRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Starts at the last pending request.&lt;br /&gt;
# Configures DMA with that request&#039;s source and byte count.&lt;br /&gt;
# Selects the first color through &amp;lt;code&amp;gt;$2121&amp;lt;/code&amp;gt; and performs the copy.&lt;br /&gt;
# Continues with earlier requests.&lt;br /&gt;
# Writes &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; when finished.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; macros also update the color copies and effect state:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Without the global effect:&#039;&#039;&#039; request the upload and update SMW&#039;s buffers, preventing the game from reusing old colors during the goal victory animation.&lt;br /&gt;
* &#039;&#039;&#039;With the global effect:&#039;&#039;&#039; store the original colors and prepare the state needed to apply the effect before sending them to CGRAM.&lt;br /&gt;
&lt;br /&gt;
=== Automatic assignment ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable or table !! Total bytes !! Bytes per value !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 32 || 2 || ID assigned to each destination. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; marks a free entry; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; marks one set aside.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 16 || 1 || Protects each destination from automatic replacement while in use.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 || 1; one bit per sprite palette || Tracks sprite palettes assigned with the global effect enabled. Sharing an assignment also requires this setting to match.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The search follows this order:&lt;br /&gt;
&lt;br /&gt;
# Reuse an assignment with the same ID and compatible effect setting.&lt;br /&gt;
# If none exists, use a free entry.&lt;br /&gt;
# If none is free, replace an entry that is not set aside and whose timer is 0.&lt;br /&gt;
# If no entry qualifies, report assignment failure.&lt;br /&gt;
&lt;br /&gt;
While using the palette, the resource keeps its timer at 2. Reaching 0 does not erase the colors: the assignment can still be reused if another resource has not replaced it.&lt;br /&gt;
&lt;br /&gt;
=== Manual assignment and version ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Manual with upload:&#039;&#039;&#039; code selects the destination and requests its colors.&lt;br /&gt;
* &#039;&#039;&#039;Manual without upload:&#039;&#039;&#039; code selects the destination and uses the colors already available there.&lt;br /&gt;
* &#039;&#039;&#039;Version:&#039;&#039;&#039; selects an entry in the DynamicInfo palette list. The last processed version lets the system check whether that selection changed.&lt;br /&gt;
&lt;br /&gt;
Resources choosing the same destination with different colors must coordinate their uploads. Keeping a palette protected does not mean uploading its colors again.&lt;br /&gt;
&lt;br /&gt;
== Pose drawing: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
Drawing prepares a pose&#039;s pieces in OAM: the tiles to display, their positions, and their properties. The graphics data must be in VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Drawing steps ===&lt;br /&gt;
&lt;br /&gt;
# Finds the pose&#039;s routine and data through &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Gets the tile count from &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Calculates each tile&#039;s position from the sprite position, displacements, and applicable flips.&lt;br /&gt;
# Checks whether the tile is visible and OAM space remains.&lt;br /&gt;
# Writes its position, tile number, properties, and size to the OAM buffers.&lt;br /&gt;
&lt;br /&gt;
The tile number depends on the drawing type:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Case !! How the tile is selected&lt;br /&gt;
|-&lt;br /&gt;
| Dynamic pose || Adjusted to the graphics&#039; location in VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| Static pose || Uses its fixed tile number.&lt;br /&gt;
|-&lt;br /&gt;
| Pose using a shared tile || Code must set &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; before drawing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Priority and available space ===&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;LoROM&#039;&#039;&#039;, the system tracks available OAM entries itself.&lt;br /&gt;
* In &#039;&#039;&#039;SA-1&#039;&#039;&#039;, it integrates with MaxTile.&lt;br /&gt;
* &#039;&#039;&#039;Drawing priority&#039;&#039;&#039; orders sprite tiles. It is separate from the property that places a tile in front of or behind layers.&lt;br /&gt;
* SNES &#039;&#039;&#039;per-scanline limits&#039;&#039;&#039; still apply. Loading a pose does not guarantee that all its tiles can be displayed.&lt;br /&gt;
&lt;br /&gt;
== Player and Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
The original player has its own routines to select and upload pose pieces. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; integrates that work with Dynamic Xtreme uploads and lets you change the graphics and palette sources.&lt;br /&gt;
&lt;br /&gt;
With the original format, the game still selects the pose pieces. The routine gets their addresses from the configured source and compares them with the previous addresses to upload only those that changed.&lt;br /&gt;
&lt;br /&gt;
These uploads use forced transfers, and their bytes also count toward later normal requests. They retain priority while remaining part of the system&#039;s data budget.&lt;br /&gt;
&lt;br /&gt;
The player&#039;s palette receives special handling: it combines the game&#039;s own colors and selections with the custom source. It is more involved than replacing an ordinary sprite&#039;s entire palette.&lt;br /&gt;
&lt;br /&gt;
Support for custom players lets other systems handle their poses and drawing differently. It does not automatically convert any spritesheet to the original player&#039;s format.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi also uploads graphics in pieces. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; lets you change their source while retaining the layout expected by the routines.&lt;br /&gt;
&lt;br /&gt;
The code calculates which pieces are needed and prepares uploads to the corresponding VRAM destinations. Like the player&#039;s uploads, these receive priority handling.&lt;br /&gt;
&lt;br /&gt;
This option requires &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; and shares its compatibility restrictions. Enabling Yoshi&#039;s features alone does not avoid a conflict with the player system.&lt;br /&gt;
&lt;br /&gt;
== Memory and optimizations ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW keeps original player, Yoshi, and some animation graphics in RAM. In ROMs without SA-1, this option adapts uploads to read that data from ROM instead.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme uses the recovered RAM for its internal variables. It is not free space for other code to overwrite.&lt;br /&gt;
&lt;br /&gt;
SA-1 uses different addresses and disables this option. See the ranges in [[Dynamic_Xtreme#RAM_usage|RAM usage]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
This option moves controller processing from NMI to the game mode code. It frees time for screen updates without adding a frame of input delay or changing which buttons the game receives.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
The console uses the fixed color for color math. To update it, the game prepares its components and sends them to the corresponding register.&lt;br /&gt;
&lt;br /&gt;
This optimization replaces that preparation with a shorter sequence. The color is still sent to the console, with less work required during NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic uses lists called stripe images to update parts of the tilemaps. These contain both the data and destination information.&lt;br /&gt;
&lt;br /&gt;
The integrated version of Kevin&#039;s optimization prepares part of the destination adjustment outside NMI, leaving less setup work for transfer time.&lt;br /&gt;
&lt;br /&gt;
This option replaces the standalone original patch. It must not be uninstalled after installation; keep this in mind before enabling it.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
The original status bar updates specific VRAM regions. This option prepares its transfers more directly, reducing the DMA setup needed during NMI.&lt;br /&gt;
&lt;br /&gt;
It modifies updates to the original status bar rather than adding a new one. As a result, it conflicts with resources that replace, modify, or remove that bar.&lt;br /&gt;
&lt;br /&gt;
== Dynamic sprites: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
The system works as a &#039;&#039;&#039;pose cache in VRAM&#039;&#039;&#039;. Instead of keeping a graphics copy for each sprite, it stores a pose that every resource needing it can reuse.&lt;br /&gt;
&lt;br /&gt;
* A pose is uploaded only once while it remains in the cache.&lt;br /&gt;
* Later requests update its last-use time without adding another graphics upload.&lt;br /&gt;
* A pose is not erased when a resource stops using it. It stays until its space is needed and it is selected for replacement.&lt;br /&gt;
* If replaced and later requested again, it must be uploaded again.&lt;br /&gt;
&lt;br /&gt;
Replacement depends on &#039;&#039;&#039;time since last use&#039;&#039;&#039;, not time since upload, as well as whether the space fits the new pose.&lt;br /&gt;
&lt;br /&gt;
=== Three different values ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Value !! What it identifies&lt;br /&gt;
|-&lt;br /&gt;
| Pose ID || The installed pose. A 16-bit value used to look up its data in ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Hash table index || The RAM entry that records the pose. Ranges from 0 to 127.&lt;br /&gt;
|-&lt;br /&gt;
| VRAM block || ID of one of the 128 16×16 tile positions in sprite VRAM. Numbered left to right and top to bottom, from 0 to 127. A pose occupying several blocks stores its first block&#039;s ID.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The hash table index and VRAM block do not need to match. A table entry can record a pose starting at any allowed block.&lt;br /&gt;
&lt;br /&gt;
=== Registered pose tables ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable or table !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 || 1 || Number of registered poses.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 || 1 || Number of registered poses for each hash.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 256 || 2 || Full pose ID in each entry. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; marks a free entry.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Starting VRAM block of each pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 256 || 2 || &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; value at the pose&#039;s last use.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These tables occupy &#039;&#039;&#039;769 bytes&#039;&#039;&#039; of RAM. They track poses registered during gameplay, whereas the DynamicInfo-generated tables describe every installed pose.&lt;br /&gt;
&lt;br /&gt;
=== Looking up a pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicPoseHashmap_FindPose&amp;lt;/code&amp;gt; uses a 128-entry hash table. The hash selects where to start searching:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hash = pose ID AND $007F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Different IDs can share a hash. For example, &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; both produce &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;. The hash alone therefore cannot confirm that a pose is loaded; the full ID must also match.&lt;br /&gt;
&lt;br /&gt;
The search follows these steps:&lt;br /&gt;
&lt;br /&gt;
# Saves the requested ID and calculates its hash.&lt;br /&gt;
# If &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; is 0, no poses are registered and the search ends.&lt;br /&gt;
# Checks &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize[hash]&amp;lt;/code&amp;gt;. If it is 0, no registered pose has that hash, so the search also ends.&lt;br /&gt;
# Starts at the entry whose index matches the hash.&lt;br /&gt;
# Reads that entry&#039;s ID. If it matches the requested ID, the pose has been found.&lt;br /&gt;
# Otherwise, continues to the next entry in the search sequence.&lt;br /&gt;
&lt;br /&gt;
The sequence advances &#039;&#039;&#039;15 entries per attempt&#039;&#039;&#039;, wrapping around after 127:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
next index = (current index + 15) AND $7F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With 128 entries, this step visits every position before repeating one. For hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, the sequence starts:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$05 → $14 → $23 → $32 → $41 → ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The pose count for each hash ====&lt;br /&gt;
&lt;br /&gt;
Each hash has its own counter in &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt;. For example, if two registered poses have IDs that produce hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize+$05&amp;lt;/code&amp;gt; contains 2.&lt;br /&gt;
&lt;br /&gt;
This number tells the search &#039;&#039;&#039;how many poses have that hash&#039;&#039;&#039;, not how many positions to visit. The search uses a temporary copy of the counter:&lt;br /&gt;
&lt;br /&gt;
# Starts with the registered pose count for the requested hash.&lt;br /&gt;
# Visits positions in the sequence until it finds the requested ID or has checked that many poses with the same hash.&lt;br /&gt;
# Each time it finds a pose with the same hash but a different ID, decrements the temporary counter.&lt;br /&gt;
# Free positions and poses with other hashes do not decrement it; the search continues.&lt;br /&gt;
# If the temporary counter reaches 0 without finding the ID, the requested pose is not registered and the search ends.&lt;br /&gt;
&lt;br /&gt;
The counter in &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; does not change during lookup. It changes only when poses are added to or removed from the cache.&lt;br /&gt;
&lt;br /&gt;
For example, suppose the requested ID is &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt;, which produces hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, and that hash&#039;s counter is 2:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Visited position !! Stored ID !! ID&#039;s hash !! Hash $05 poses still to check&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 1: same hash, but a different ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0014&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || 1: different hash, so the counter is unchanged.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$23&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 0: both poses with this hash have been checked. &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt; is not registered.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Usually, each hash has one or two poses. This allows lookup with few comparisons and a typical cost close to &amp;lt;code&amp;gt;O(1)&amp;lt;/code&amp;gt;. It does not mean only one or two positions are always visited: entries with other hashes may lie between them. Many collisions can make the search longer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A free entry does not end the search.&#039;&#039;&#039; It may have been emptied by replacing a pose, with another pose of the same hash still farther along the sequence. The counter tells the search when all poses with that hash have been checked, even with gaps between them.&lt;br /&gt;
&lt;br /&gt;
==== When the pose is found ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Gets the matching entry&#039;s index.&lt;br /&gt;
# Writes the current &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; value to that entry&#039;s &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reports request success without scheduling another graphics upload.&lt;br /&gt;
&lt;br /&gt;
All resources requesting that ID therefore use the same pose and keep it protected. They may be normal, cluster, or extended sprites, or any other code using the system.&lt;br /&gt;
&lt;br /&gt;
This also prevents duplicate uploads within one cycle: once the first request is accepted, the pose is registered even though the actual transfer will occur during NMI.&lt;br /&gt;
&lt;br /&gt;
=== When the pose is not registered ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt; proceeds with a new upload:&lt;br /&gt;
&lt;br /&gt;
# Reads &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; and calculates &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend + PoseSize&amp;lt;/code&amp;gt;.&lt;br /&gt;
# If the result exceeds &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, returns failure without changing existing poses.&lt;br /&gt;
# Reads &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; to find the required block count.&lt;br /&gt;
# Calls &amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; to find suitable space.&lt;br /&gt;
# If no usable space exists, returns failure.&lt;br /&gt;
# Removes poses occupying the chosen space from the map and hash table.&lt;br /&gt;
# Finds a free hash table entry and registers the new pose.&lt;br /&gt;
# Updates the VRAM map and frame data counter.&lt;br /&gt;
# Calls &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; to add the transfers.&lt;br /&gt;
&lt;br /&gt;
The budget check happens before replacing poses. If the new upload cannot fit in the frame, no space is freed for a request that cannot be fulfilled.&lt;br /&gt;
&lt;br /&gt;
==== Adding and removing hash table entries ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_FindFreeSpace&amp;lt;/code&amp;gt; looks for an entry whose ID is &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt;, using the same sequence of 15-entry steps.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; stores the ID and last-use time, increments &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt;, and increments the corresponding hash counter.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Remove&amp;lt;/code&amp;gt; writes &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; to the removed ID and decrements both counters.&lt;br /&gt;
&lt;br /&gt;
Removing an entry does not itself erase VRAM pixels. It marks the pose as unavailable in the cache; the new transfers overwrite the chosen space.&lt;br /&gt;
&lt;br /&gt;
=== Representing the VRAM map ===&lt;br /&gt;
&lt;br /&gt;
The map represents &#039;&#039;&#039;128 16×16 tile positions in sprite VRAM&#039;&#039;&#039;, numbered left to right and top to bottom. Each block is one of those positions, not a contiguous 128-byte range.&lt;br /&gt;
&lt;br /&gt;
A 16×16 tile consists of four 8×8 tiles arranged in two rows. The map manages the positions occupied by a pose; &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; later handles how its data must be distributed for upload.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Section&#039;s starting position. Bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; marks it as restricted: dynamic poses cannot use this space.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt;, also called &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 || 1 || If bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; is set, the remaining bits hold the section&#039;s position count minus one. Otherwise, they hold the occupying pose&#039;s hash index. Check &amp;lt;code&amp;gt;Offset&amp;lt;/code&amp;gt; to determine whether the space is restricted.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These two tables occupy &#039;&#039;&#039;256 bytes&#039;&#039;&#039;. Together with the pose tables, the manager uses &#039;&#039;&#039;1025 bytes&#039;&#039;&#039; of RAM, excluding transfer lists and working scratch memory.&lt;br /&gt;
&lt;br /&gt;
=== Map sections ===&lt;br /&gt;
&lt;br /&gt;
A section groups consecutive map positions that are restricted, free, or occupied by one pose. Its information is stored at &#039;&#039;&#039;the first and last positions&#039;&#039;&#039;, allowing traversal to jump to the previous section without checking every position in between.&lt;br /&gt;
&lt;br /&gt;
The following examples show three possible states for a 6-position section from &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;. These are alternatives, not three sections occupying the same space at once.&lt;br /&gt;
&lt;br /&gt;
==== Example 1: restricted section ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table entries !! Value !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$A0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; marks the restriction; &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; identifies the start.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$85&amp;lt;/code&amp;gt; || The section has 6 positions: &amp;lt;code&amp;gt;($85 AND $7F) + 1 = 6&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Although the high bit of &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt; is set, &#039;&#039;&#039;this space is not free for dynamic poses&#039;&#039;&#039;: the restriction bit in &amp;lt;code&amp;gt;Offset&amp;lt;/code&amp;gt; excludes it. It is not evaluated as a replaceable pose.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; uses this section type to exclude parts of SP1–SP4 that dynamic sprites must not use.&lt;br /&gt;
&lt;br /&gt;
==== Example 2: free section ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table entries !! Value !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || Starts at &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; and is not restricted.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$85&amp;lt;/code&amp;gt; || Bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; marks a free section&#039;s size: &amp;lt;code&amp;gt;$05 + 1 = 6&amp;lt;/code&amp;gt; positions.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This section is available. It can hold a pose needing up to 6 positions; placing a 4-position pose leaves the other 2 as a separate free section.&lt;br /&gt;
&lt;br /&gt;
==== Example 3: section occupied by a pose ====&lt;br /&gt;
&lt;br /&gt;
Suppose a 6-block pose is registered at hash entry &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; and occupies positions &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table entries !! Value !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || The section starts at &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; and is not restricted.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || Bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; is clear: &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; is the pose&#039;s hash index, not its block count.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To find the position count and time since last use:&lt;br /&gt;
&lt;br /&gt;
# Read the pose ID at &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID+$0E&amp;lt;/code&amp;gt;. The offset is &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; because each ID occupies 2 bytes and &amp;lt;code&amp;gt;$07 × 2 = $0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Use that ID to read &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt;, which contains 6 in this example.&lt;br /&gt;
# Read &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse+$0E&amp;lt;/code&amp;gt; to calculate how long the pose has gone unused.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset+$07&amp;lt;/code&amp;gt; stores &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;, connecting the registered pose to its VRAM position.&lt;br /&gt;
&lt;br /&gt;
=== Traversal and space search ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; starts at 16×16 tile position &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt;. To traverse the map:&lt;br /&gt;
&lt;br /&gt;
# Reads &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; at the current position.&lt;br /&gt;
# Gets the section&#039;s start with &amp;lt;code&amp;gt;Offset AND $7F&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Evaluates that section and spaces it can form with adjacent sections.&lt;br /&gt;
# Moves to &amp;lt;code&amp;gt;section start - 1&amp;lt;/code&amp;gt;, the previous section&#039;s last position.&lt;br /&gt;
# Repeats until reaching the beginning of the map.&lt;br /&gt;
&lt;br /&gt;
For example, if the last sections start at &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Visited position !! Start read from Offset !! Next position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4F&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This traverses &#039;&#039;&#039;whole sections&#039;&#039;&#039;, not every tile in between.&lt;br /&gt;
&lt;br /&gt;
==== What the traversal evaluates ====&lt;br /&gt;
&lt;br /&gt;
A candidate space can consist of &#039;&#039;&#039;one section or several adjacent sections&#039;&#039;&#039;. At each step, the search checks:&lt;br /&gt;
&lt;br /&gt;
* A restricted section cannot be used, and sections cannot be combined across it.&lt;br /&gt;
* A pose protected by recent use cannot be part of the space either.&lt;br /&gt;
* If the candidate is still too small, an adjacent section can be added to reach the required block count.&lt;br /&gt;
* Once the pose fits, the candidate is compared with the best one found: first by its time-since-last-use score, then by the smallest sufficient space.&lt;br /&gt;
&lt;br /&gt;
A section is not chosen merely because it contains the longest-unused pose. The &#039;&#039;&#039;whole space&#039;&#039;&#039; must fit the new pose. When combining sections, the score depends on the most recently used pose within that space.&lt;br /&gt;
&lt;br /&gt;
The search keeps these temporary values:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Working data !! Total bytes !! Bytes per value !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapCurrentSpace&amp;lt;/code&amp;gt; || 3 || 1 per field || Start, score, and block count of the current candidate.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapBestSpace&amp;lt;/code&amp;gt; || 3 || 1 per field || Same fields for the best candidate found.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapTMP_Size&amp;lt;/code&amp;gt; || 1 || 1 || Block count needed by the new pose.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These names refer to working scratch memory, not additional persistent RAM.&lt;br /&gt;
&lt;br /&gt;
=== Replacement policy: time since last use and enough space ===&lt;br /&gt;
&lt;br /&gt;
The system does not simply choose the first pose uploaded. It uses the time since the pose&#039;s &#039;&#039;&#039;last use&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
time since last use = DX_Timer - pose TimeLastUse&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMapSlot_GetSizeAndScore&amp;lt;/code&amp;gt; gets each region&#039;s size and score:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Case !! Score and handling&lt;br /&gt;
|-&lt;br /&gt;
| Free region || &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Preferred over occupied regions.&lt;br /&gt;
|-&lt;br /&gt;
| Occupied region || Time since last use, capped at &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Unused for 0 or 1 timer increments || Cannot be replaced: the pose is still protected.&lt;br /&gt;
|-&lt;br /&gt;
| Restricted region || Excluded: dynamic poses cannot use this space.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Protection requires &#039;&#039;&#039;at least two increments of &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; without using the pose&#039;&#039;&#039; before it can be replaced. Each resource requesting it again updates its last-use time and protects it again.&lt;br /&gt;
&lt;br /&gt;
==== Why the longest-unused pose is not always replaced ====&lt;br /&gt;
&lt;br /&gt;
The new pose needs enough contiguous space. A small space alone is not useful, even if it has gone unused for a long time.&lt;br /&gt;
&lt;br /&gt;
For example, consider a new pose needing 4 blocks:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Candidate space !! Time since last use !! Suitable?&lt;br /&gt;
|-&lt;br /&gt;
| Pose A: 2 blocks, with no usable adjacent space || 20 || No: frees only 2 blocks.&lt;br /&gt;
|-&lt;br /&gt;
| Pose B: 4 blocks || 8 || Yes: fits the new pose.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Here, B can be replaced while A stays. A has gone unused longer, but its space cannot satisfy the request.&lt;br /&gt;
&lt;br /&gt;
If two or more adjacent regions can be replaced, the system can consider them together. It then:&lt;br /&gt;
&lt;br /&gt;
* Adds their block counts.&lt;br /&gt;
* Uses the &#039;&#039;&#039;lowest score&#039;&#039;&#039; among them: the shortest time since last use.&lt;br /&gt;
* Excludes any restricted or protected region from the combined space.&lt;br /&gt;
&lt;br /&gt;
This prevents a recently used pose from being overwritten just because it is next to a long-unused one.&lt;br /&gt;
&lt;br /&gt;
==== Choosing among valid candidates ====&lt;br /&gt;
&lt;br /&gt;
# The candidate must have at least the requested block count.&lt;br /&gt;
# The highest score wins: free space or the longest time since last use.&lt;br /&gt;
# If scores match, the smaller candidate wins, provided the pose fits.&lt;br /&gt;
# If score and size both match, the previously chosen candidate is kept.&lt;br /&gt;
&lt;br /&gt;
Regions are combined during the search when the candidate is still too small. The system does not combine every replaceable region regardless of the requested size.&lt;br /&gt;
&lt;br /&gt;
=== Replacing and splitting the chosen region ===&lt;br /&gt;
&lt;br /&gt;
Once the space is chosen:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemovePosesInSpace&amp;lt;/code&amp;gt; traverses its regions and removes poses being replaced from the hash table.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemoveSpace&amp;lt;/code&amp;gt; marks the chosen space as one free region by updating its endpoints.&lt;br /&gt;
# A free hash entry is found, and the starting block is stored in &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; registers the pose.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_AddPoseInSpace&amp;lt;/code&amp;gt; writes the pose&#039;s hash index and region start at the first and last blocks.&lt;br /&gt;
# Any leftover blocks become another free region.&lt;br /&gt;
&lt;br /&gt;
If a 6-block region holds a 4-block pose, it becomes a 4-block occupied region and a 2-block free region. Other poses are not moved to compact VRAM.&lt;br /&gt;
&lt;br /&gt;
=== DynamicRoutine: preparing pose transfers ===&lt;br /&gt;
&lt;br /&gt;
At this point, space has been chosen and the pose registered. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; turns that allocation into transfer requests.&lt;br /&gt;
&lt;br /&gt;
It uses these values:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Data !! Amount read per pose !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Starting block || 1 byte || Position chosen by the VRAM map.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; || 2 bytes from a 256-byte table || Converts one of the 128 blocks to a VRAM offset.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 bytes || Full ROM address of the pose data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 bytes: two 2-byte values || Byte counts of the first and second sections.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 bytes || VRAM offset for the second section.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Converting the block to a VRAM address ====&lt;br /&gt;
&lt;br /&gt;
A 16×16 block does not convert to a simple linear byte offset. Each block uses 8×8 tiles distributed across VRAM rows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; accounts for that layout. For example:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Block !! Offset !! VRAM address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These VRAM addresses are measured in 2-byte words, not bytes. The routine adds the &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; base used for sprite graphics.&lt;br /&gt;
&lt;br /&gt;
==== Processing sections and rows ====&lt;br /&gt;
&lt;br /&gt;
# Gets the source from &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Processes the first section&#039;s bytes through &amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt;.&lt;br /&gt;
# If the second section&#039;s size is 0, returns.&lt;br /&gt;
# Otherwise, advances the source by the first section&#039;s byte count.&lt;br /&gt;
# Adds &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; to the VRAM offset and processes the second section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt; splits each section according to its rows and starting position. For destination V measured in VRAM words, it prepares:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
First row end = (V + $0100) AND $FF00&lt;br /&gt;
Bytes to that end = (first row end - V) × 2&lt;br /&gt;
Second part destination = first row end + $0100&lt;br /&gt;
Second part bytes in a group = $0200 - first part bytes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sizes are byte counts, while VRAM destinations are word addresses. This is why the calculation multiplies by 2 to find how many bytes fit before the end of a row.&lt;br /&gt;
&lt;br /&gt;
The routine uses three paths:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt;: adds one final request for the remaining bytes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLinesWithEndLine&amp;lt;/code&amp;gt;: adds two requests for the remaining data, each with its own destination and byte count.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLines&amp;lt;/code&amp;gt;: adds two requests totaling &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, advances the source and destinations, and repeats for the remaining data.&lt;br /&gt;
&lt;br /&gt;
A direct path precedes the general loop: if the destination starts on a &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt;-word boundary and the section contains at least &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, the routine uses &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt; to prepare the entire section as one request.&lt;br /&gt;
&lt;br /&gt;
For example, a &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt;-byte section starting at &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; is split as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Request !! Source !! VRAM destination !! Bytes&lt;br /&gt;
|-&lt;br /&gt;
| First || Section start || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt;: 448&lt;br /&gt;
|-&lt;br /&gt;
| Second || Section start + &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0040&amp;lt;/code&amp;gt;: 64&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Together, the two requests copy the section&#039;s 512 bytes to the destinations calculated from the row layout. They are not two complete copies of the pose.&lt;br /&gt;
&lt;br /&gt;
Each request uses these tables:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each added request increments &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The pose&#039;s total byte count was already checked and added to &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;. This stage splits that upload into transfers; it does not count the full pose again for each request.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; &#039;&#039;&#039;does not run DMA&#039;&#039;&#039;. It prepares requests for &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt; to process during NMI.&lt;br /&gt;
&lt;br /&gt;
=== What the sprite keeps ===&lt;br /&gt;
&lt;br /&gt;
Sprite routines store the usable pose&#039;s hash index, not a separate copy of its graphics. The index lets them look up its VRAM block and update its last-use time.&lt;br /&gt;
&lt;br /&gt;
If a new pose cannot be loaded:&lt;br /&gt;
&lt;br /&gt;
* A valid previous pose is kept, and its last-use time is updated to protect it.&lt;br /&gt;
* If no valid pose has ever been available, the code must not draw as though the request succeeded.&lt;br /&gt;
* Calls supporting fallback to the previous pose may return carry set because a pose is still usable, even though the change has not completed.&lt;br /&gt;
&lt;br /&gt;
Animation and movement remain the sprite&#039;s responsibility. The cache reuses or prepares the requested graphics.&lt;br /&gt;
&lt;br /&gt;
=== Example: two sprites request the same pose ===&lt;br /&gt;
&lt;br /&gt;
Suppose two visible sprites, A and B, need dynamic pose &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt;. Their palettes are ready, the pose is not yet in VRAM, and enough space and data budget remain.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Sprite A requests the pose.&#039;&#039;&#039; Lookup does not find &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; in the cache. The system chooses space, registers the pose, and prepares its graphics transfers. A stores the entry index in &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;. The graphics have not been copied to VRAM yet.&lt;br /&gt;
# &#039;&#039;&#039;A prepares its drawing.&#039;&#039;&#039; The drawing routine uses the registered entry to calculate tile numbers for that VRAM space and writes positions and properties to the OAM buffers.&lt;br /&gt;
# &#039;&#039;&#039;Sprite B requests the same pose.&#039;&#039;&#039; Lookup now finds &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; registered, even though its transfer is pending. It updates the last-use time without scheduling another upload. B stores the same cache index in its own &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &#039;&#039;&#039;B prepares its drawing.&#039;&#039;&#039; It writes its own tiles to the OAM buffers, using the same graphics as A with its own position, palette, and flip settings.&lt;br /&gt;
# &#039;&#039;&#039;NMI updates video data.&#039;&#039;&#039; The pending pose transfers copy the graphics to VRAM, and the game transfers the OAM buffers. Both sprites use the same uploaded graphics in the next displayed frame.&lt;br /&gt;
&lt;br /&gt;
Only one pose upload is prepared, even though two sprites use it. That upload may require several DMA transfers, depending on the graphics layout in VRAM.&lt;br /&gt;
&lt;br /&gt;
Here, a pose being &#039;&#039;&#039;available&#039;&#039;&#039; during logic means it has a registered entry, allocated space, and an upload prepared for NMI. If its graphics were already in VRAM, they are reused directly without preparing another transfer.&lt;br /&gt;
&lt;br /&gt;
If A&#039;s request were rejected, the new pose would not be registered and no upload would be pending. A would use its previous pose if available; otherwise, it would have no pose to draw. B would need to handle its own request and would not find an entry created by A&#039;s rejected attempt.&lt;br /&gt;
&lt;br /&gt;
== Palette effects: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
The system keeps the original colors so it can change effects, combine them, or restore the unaffected palette. An already affected result must not be treated as the original palette.&lt;br /&gt;
&lt;br /&gt;
=== Color buffers ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable or buffer !! Total bytes !! Bytes per value !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 || 2 per color || Base colors in SNES format, with 2 bytes per color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 || 3 per color || Base colors split into red, green, and blue, with 3 bytes per color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 || 3 per color || Base colors split into hue, saturation, and lightness, with 3 bytes per color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 || 2 per color || SNES-format result, ready for a CGRAM transfer request. Corresponds to the game&#039;s palette buffer.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Per-palette flags ===&lt;br /&gt;
&lt;br /&gt;
Each bit in these flags corresponds to one palette. &amp;lt;code&amp;gt;BG&amp;lt;/code&amp;gt; variables cover 0–7; &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt; variables cover 8–F.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variables !! Total bytes !! Bytes per value !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseLoaded&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseLoaded&amp;lt;/code&amp;gt; || 1 per variable; 2 combined || 1; one bit per palette || Whether the SNES-format color base has been prepared.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 per variable; 2 combined || 1; one bit per palette || Whether the base has been converted to RGB.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 per variable; 2 combined || 1; one bit per palette || Whether the base has been converted to HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 per variable; 2 combined || 1; one bit per palette || Whether the global effect result is ready.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These flags avoid repeating conversions and calculations whose results remain valid.&lt;br /&gt;
&lt;br /&gt;
=== Preparing a base ===&lt;br /&gt;
&lt;br /&gt;
# Checks whether the palette already has a registered base.&lt;br /&gt;
# If not, gets the colors from the game&#039;s buffer. An explicit upload, such as &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, can supply that base directly.&lt;br /&gt;
# Checks whether the effect needs RGB or HSL.&lt;br /&gt;
# If that conversion is missing, prepares it and marks it as available.&lt;br /&gt;
&lt;br /&gt;
If only the effect changes, the base may remain valid. If the original colors change, upload calls update the base and invalidate conversions and results that must be recalculated.&lt;br /&gt;
&lt;br /&gt;
=== Effect data ===&lt;br /&gt;
&lt;br /&gt;
The ID selects data from the tables generated during installation:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt;: calculation to perform.&lt;br /&gt;
* &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt;: channel values, or a transition&#039;s target palette address.&lt;br /&gt;
* &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt;: how much of each change to apply.&lt;br /&gt;
&lt;br /&gt;
Channels range from 0 to 31. Ratios range from 0 to 127: 0 keeps the source unchanged, and 127 fully applies the selected change.&lt;br /&gt;
&lt;br /&gt;
Calculations run outside NMI. NMI transfers the resulting colors.&lt;br /&gt;
&lt;br /&gt;
=== Global effect ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Total bytes !! Bytes per value !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 || 2 || Selects the global effect. 0 restores the base colors.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 || 1; one bit per palette || Selects palettes 0–7 to receive the effect.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 || 1; one bit per palette || Selects palettes 8–F to receive the effect.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 32 || 2 || Last global effect ID processed for each palette.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 || 1 || Controls whether the fixed color and color 0,0 are affected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For each enabled palette, the manager:&lt;br /&gt;
&lt;br /&gt;
# Checks whether the effect result needs an update.&lt;br /&gt;
# Prepares the RGB or HSL base if missing.&lt;br /&gt;
# Calculates the effect if the previous result is no longer valid.&lt;br /&gt;
# Prepares SNES-format colors and requests their transfer.&lt;br /&gt;
# Records the processed ID when the corresponding upload is accepted.&lt;br /&gt;
&lt;br /&gt;
If the effect and base remain unchanged, recalculation is unnecessary. Changing the global ID invalidates previous results, but not necessarily the RGB and HSL bases.&lt;br /&gt;
&lt;br /&gt;
Global ID 0 also requires an update: the system must upload the base colors again to remove the previous effect.&lt;br /&gt;
&lt;br /&gt;
=== Local effects and concatenation ===&lt;br /&gt;
&lt;br /&gt;
A resource can have its own effect and also receive the global effect. For example, a sprite can change hue and then darken along with the level.&lt;br /&gt;
&lt;br /&gt;
The order is:&lt;br /&gt;
&lt;br /&gt;
# Prepare the local effect result.&lt;br /&gt;
# Use it as the global effect&#039;s base through the concatenation call.&lt;br /&gt;
# Calculate the global effect on that base.&lt;br /&gt;
# Upload the combined result without first displaying the local-only version.&lt;br /&gt;
&lt;br /&gt;
* Use RGB concatenation for RGB effects.&lt;br /&gt;
* Use HSL concatenation for HSL effects.&lt;br /&gt;
* Resources sharing a CGRAM destination share its colors. To display two different local effects, they need destinations that can keep both results separately.&lt;br /&gt;
&lt;br /&gt;
=== If the transfer is rejected ===&lt;br /&gt;
&lt;br /&gt;
* Calculating an effect does not mean it is already in CGRAM.&lt;br /&gt;
* If the transfer is rejected, the manager can retry the update.&lt;br /&gt;
* Where supported, the previous usable result is kept until it can be replaced.&lt;br /&gt;
* Do not upload the unaffected original colors first: they could appear for one frame before the correct result.&lt;br /&gt;
&lt;br /&gt;
== How the systems work together ==&lt;br /&gt;
&lt;br /&gt;
A dynamic sprite brings these tasks together:&lt;br /&gt;
&lt;br /&gt;
# Its logic selects the pose and palette version.&lt;br /&gt;
# Palette assignment finds a usable palette and prepares colors if needed.&lt;br /&gt;
# The cache protects the loaded pose or prepares a new upload.&lt;br /&gt;
# Drawing writes the pose&#039;s tiles to the OAM buffers.&lt;br /&gt;
# The effect manager prepares pending global changes.&lt;br /&gt;
# NMI performs the requested graphics and color transfers.&lt;br /&gt;
&lt;br /&gt;
Sharing graphics, sharing a palette, and sharing a drawing routine are three different things. Dynamic Xtreme can take advantage of each without requiring resources to share the others.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_ASM_API&amp;diff=21397</id>
		<title>Dynamic Xtreme ASM API</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_ASM_API&amp;diff=21397"/>
		<updated>2026-10-25T21:57:36Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: Created page with &amp;quot;{{Select Language|Dynamic_Xtreme_ASM_API}}  This article explains how to use Dynamic Xtreme&amp;#039;s routines and macros from ASM code. Each entry explains the call&amp;#039;s purpose, inputs, and results, with an example.  To learn how to organize a complete sprite, see the sprite creation guide.  == Features required to use the API ==  Available routines, macros, and variables depend on the features selected when installing Dynamic Xtreme. This...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_ASM_API}}&lt;br /&gt;
&lt;br /&gt;
This article explains how to use Dynamic Xtreme&#039;s routines and macros from ASM code. Each entry explains the call&#039;s purpose, inputs, and results, with an example.&lt;br /&gt;
&lt;br /&gt;
To learn how to organize a complete sprite, see the [[Dynamic_Xtreme_sprite_creation_guide|sprite creation guide]].&lt;br /&gt;
&lt;br /&gt;
== Features required to use the API ==&lt;br /&gt;
&lt;br /&gt;
Available routines, macros, and variables depend on the features selected when installing Dynamic Xtreme. This table shows what to enable for each system:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Available routines and macros !! Dependencies and details&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;&lt;br /&gt;
| [[#PPU|VRAM transfers]]: &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt; and its &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WithLenght&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; variants.&lt;br /&gt;
| Provides graphics loading. Also required by &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;&lt;br /&gt;
| [[#DefineDynamicSpaceConfig|DefineDynamicSpaceConfig]], [[#DynamicPoseSpaceConfig|DynamicPoseSpaceConfig]], [[#TakeDynamicRequest|TakeDynamicRequest]], [[#DynamicRoutine|DynamicRoutine]], &amp;lt;code&amp;gt;SetPropertyAndOffset&amp;lt;/code&amp;gt;, [[#Upload|!Upload]], &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;, and the general macros &amp;lt;code&amp;gt;GeneralUpload&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Upload&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;StandardSpriteUpload&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Requires &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;. Drawing the obtained poses also requires &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;&lt;br /&gt;
| [[#DXDraw|!DXDraw]], &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt;, and general macros &amp;lt;code&amp;gt;Draw&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;StandardSpriteDraw&amp;lt;/code&amp;gt;, and [[#DrawStatic|DrawStatic]]. Includes the system&#039;s drawing and tile validation routines.&lt;br /&gt;
| Dynamic pose drawing also requires &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;DrawStatic&amp;lt;/code&amp;gt; can draw static poses without the dynamic pose system.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;AssignPalette&amp;lt;/code&amp;gt;, [[#PaletteAssignment|!PaletteAssignment]], &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, and their general macros; &amp;lt;code&amp;gt;LoadPaletteIDAndAddress&amp;lt;/code&amp;gt;; [[#Uploading_colors_with_TransferPalette|TransferPalette]] macros and [[#PPU|CGRAM transfers]].&lt;br /&gt;
| Provides palette assignment and loading. Effects additionally require &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;&lt;br /&gt;
| [[#Palette_effects|SetRGBBase, SetHSLBase, Mix, MixAndMerge, PaletteTransition, DoEffect, and RGB/HSL conversions]], including their variants. Also enables &amp;lt;code&amp;gt;ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt;, as sprite aliases or general macros.&lt;br /&gt;
| Requires &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;. Allows global effects through palette assignment or &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;&lt;br /&gt;
| Customizes player graphics and palettes through the [[#Player_and_Yoshi|player variables]]. Does not add a separate family of calls to the categories above.&lt;br /&gt;
| Requires &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;&lt;br /&gt;
| Customizes Yoshi&#039;s graphics through the [[#Player_and_Yoshi|Yoshi variables]].&lt;br /&gt;
| Requires &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; and its dependencies.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;&lt;br /&gt;
| Adds no calls to this API.&lt;br /&gt;
| Frees and reorganizes the corresponding RAM area. Not an additional requirement for loading or drawing macros. Disabled on SA-1.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
| Add no call families to this API.&lt;br /&gt;
| Change how their respective systems work internally. These are not required for pose, drawing, palette, or math macros.&lt;br /&gt;
|-&lt;br /&gt;
| No additional feature&lt;br /&gt;
| [[#Math|Mul, Div, and their W and After... variants]].&lt;br /&gt;
| Math macros are included from &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; independently of the options above.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
PPU macros are included when &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; is enabled, but use VRAM transfers with &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; and CGRAM transfers with &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;. Asar recognizing a macro&#039;s name does not mean its required lists and variables are enabled.&lt;br /&gt;
&lt;br /&gt;
To load &#039;&#039;&#039;and draw&#039;&#039;&#039; dynamic poses, enable &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;. Add &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; if the sprite loads palettes and &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; if it uses effects.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tool integration&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Context !! Files and calls&lt;br /&gt;
|-&lt;br /&gt;
| PIXI&lt;br /&gt;
| Installation copies general defines to &amp;lt;code&amp;gt;asm/ExtraDefines&amp;lt;/code&amp;gt; and shared routines to &amp;lt;code&amp;gt;routines&amp;lt;/code&amp;gt;. For sprite aliases, include &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; as appropriate. Each entry explains type-specific differences.&lt;br /&gt;
|-&lt;br /&gt;
| UberASMTool&lt;br /&gt;
| Installation links &amp;lt;code&amp;gt;ExtraDefines/DXDefines.asm&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;other/macro_library.asm&amp;lt;/code&amp;gt;. Use general macros and patch routines with their parameters; aliases such as &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; belong to PIXI sprite defines files.&lt;br /&gt;
|-&lt;br /&gt;
| GPS&lt;br /&gt;
| Installation links &amp;lt;code&amp;gt;ExtraDefines/DXDefines.asm&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;defines.asm&amp;lt;/code&amp;gt;. Use general macros and patch routines, preparing their inputs from the block&#039;s code.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These integrations are prepared for tools configured during installation. If Asar cannot find a name, check the required feature, included files, and, for generated defines, the exact spelling in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. After changing features or resources, reinstall Dynamic Xtreme and rerun tools using its defines, as explained in the [[Dynamic_Xtreme_Quick_Start|Quick Start guide]].&lt;br /&gt;
&lt;br /&gt;
== Variables and defines ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; gathers the names Dynamic Xtreme uses for its variables, configurations, resources, and routines. Some represent runtime data; others are constants or generated during resource installation.&lt;br /&gt;
&lt;br /&gt;
General variable names start with &amp;lt;code&amp;gt;DX_&amp;lt;/code&amp;gt; and have no &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; prefix, for example &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;. Defines such as &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; do include &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt;. Keep each name&#039;s exact spelling.&lt;br /&gt;
&lt;br /&gt;
Available variables depend on installed features. You do not need to memorize them all: find the category for the system you are using.&lt;br /&gt;
&lt;br /&gt;
=== General variables ===&lt;br /&gt;
&lt;br /&gt;
In these tables, size is the number of bytes occupied by one value. Tables also list their entry count. Dynamic Xtreme maintains variables marked internal; normally use API routines to work with them.&lt;br /&gt;
&lt;br /&gt;
==== Counters and data per frame ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Size !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; || 2 bytes || Counts frames in which Dynamic Xtreme runs. Continues during pause and frozen action. Used to track each pose&#039;s last use.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; || 2 bytes || Counts frames but stops during pause or frozen action. Useful for animations that should stop with the game.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; || 2 bytes || Bytes already scheduled for transfer in the current frame. Updated by loading routines.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; || 2 bytes || Maximum bytes normal uploads can schedule per frame. &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; variants can exceed it.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Poses loaded in VRAM ====&lt;br /&gt;
&lt;br /&gt;
These internal cache tables track which poses are loaded, where they are, and which remain in use. Request poses with &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Size !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 byte || Number of poses currently registered in the cache.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 one-byte values || Helps find poses by ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 128 two-byte values || ID of each registered pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 128 one-byte values || Location of each pose&#039;s graphics in dynamic VRAM space, measured in 16×16 blocks.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 128 two-byte values || &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; at each pose&#039;s last use. Prevents replacement of graphics still being displayed.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 shared bytes || Describe free and occupied VRAM regions. Two names for the same memory.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 one-byte values || Helps traverse free and occupied VRAM regions.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Palettes and the global effect ====&lt;br /&gt;
&lt;br /&gt;
The 16-palette tables use palette order 0–F. In two-byte tables, palette 1 starts at &amp;lt;code&amp;gt;+2&amp;lt;/code&amp;gt;, palette 2 at &amp;lt;code&amp;gt;+4&amp;lt;/code&amp;gt;, and so on.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Size !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 byte || Each bit determines whether one of palettes 0–7 receives the global effect.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 byte || Each bit determines whether one of sprite palettes 8–F receives the global effect.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Desired global effect ID. Zero means no global effect.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Last global effect examined by the system, used to detect changes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 16 two-byte values || Last global effect calculated per palette. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt;: no result yet; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt;: update pending, previous result retained.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 16 two-byte values || ID associated with each palette. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; means free; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; excludes it from automatic selection.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_Updated&amp;lt;/code&amp;gt; || 16 one-byte values || Palettes already updated this frame. Internal.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 16 one-byte values || A nonzero timer protects a palette from replacement by another automatic assignment. Calls using it reset it to 2.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 byte || Tracks sprite palettes using effects. Internal palette management state.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To reserve a sprite palette against automatic selection, set its &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; entry to &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; before sprites request palettes.&lt;br /&gt;
&lt;br /&gt;
==== Color copies and effect results ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Size !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 bytes || Working copy of 256 colors at 2 bytes each. Source for &amp;lt;code&amp;gt;SetRGBBaseDefault&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;SetHSLBaseDefault&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 bytes || Original colors split into red, green, and blue: 3 bytes per color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 bytes || Original colors split into hue, saturation, and lightness: 3 bytes per color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LocalEffectBuffer&amp;lt;/code&amp;gt; || 768 bytes || Working space for a local effect result before combining it with the global effect.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LocalEffectID&amp;lt;/code&amp;gt; || 16 two-byte values || Local effect ID applied to each palette.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 bytes || Resulting colors in SNES format, 2 bytes each. &amp;lt;code&amp;gt;AndMergeDefault&amp;lt;/code&amp;gt; variants write here.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 byte each || Each bit indicates a background or sprite palette&#039;s RGB base is prepared.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 byte each || Same for HSL bases.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 byte each || Each bit indicates an available effect result for that palette.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LastPlayerPal&amp;lt;/code&amp;gt; || 2 bytes || Last processed player palette address, compared to detect changes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Writing colors to a RAM copy does not immediately send them to CGRAM. Use palette routines or a transfer to update the display. The system manages prepared-base and effect flags; they do not need clearing before each call.&lt;br /&gt;
&lt;br /&gt;
==== Fixed color and the first palette color ====&lt;br /&gt;
&lt;br /&gt;
The SNES fixed color can be used for color addition and subtraction effects. Color 0,0 is CGRAM&#039;s first entry. Dynamic Xtreme can apply the global effect to either independently.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Size !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 byte || Enables the global effect: bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; for fixed color and &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; for color 0,0. &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; enables both.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_BaseLoaded&amp;lt;/code&amp;gt; || 1 byte || Tracks saved original colors, one bit per target: &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_RGBBaseLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_ColorEffect_HSLBaseLoaded&amp;lt;/code&amp;gt; || 1 byte each || Tracks prepared RGB/HSL colors, using the same bits.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Mirror&amp;lt;/code&amp;gt; || 2 bytes || Fixed color copy used by the game&#039;s normal update.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Base&amp;lt;/code&amp;gt; || 2 bytes || Original fixed color before effects.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_RGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_FixedColor_HSLBase&amp;lt;/code&amp;gt; || 3 bytes each || Original fixed color split into RGB or HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Result&amp;lt;/code&amp;gt; || 2 bytes || Fixed color calculated after the effect.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Last global effect calculated for fixed color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Base&amp;lt;/code&amp;gt; || 2 bytes || Original color 0,0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_RGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_HSLBase&amp;lt;/code&amp;gt; || 3 bytes each || Original color 0,0 split into RGB or HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Result&amp;lt;/code&amp;gt; || 2 bytes || Desired color 0,0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Last global effect calculated for color 0,0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Update&amp;lt;/code&amp;gt; || 1 byte || Nonzero requests copying &amp;lt;code&amp;gt;Result&amp;lt;/code&amp;gt; to color 0,0 during NMI. Reset to 0 afterward.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Pending transfers ====&lt;br /&gt;
&lt;br /&gt;
These variables store copies to perform during NMI. PPU macros populate them for you. Each copy needs a source, destination, and byte count.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || Pending graphics copy count, 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || Bytes per copy, two-byte values.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || Each copy&#039;s VRAM destination, two-byte values.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || Each copy&#039;s source address, two-byte values.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || Each copy&#039;s source bank. The table reserves 2 bytes per entry.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || Pending color copy count, 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || Bytes per copy, two-byte values.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || Each copy&#039;s first destination color, one-byte values.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || Each copy&#039;s source address, two-byte values.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || Each copy&#039;s source bank.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Player and Yoshi ====&lt;br /&gt;
&lt;br /&gt;
These variables change the sources of player graphics and colors and Yoshi graphics. Graphics files must retain the layout expected by the game routines.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Size !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_Enable&amp;lt;/code&amp;gt; || 1 byte || Zero disables player graphics loading through this system; nonzero enables it.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_Addr&amp;lt;/code&amp;gt; || 2 bytes || Player graphics start address within the specified bank.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_BNK&amp;lt;/code&amp;gt; || 2 bytes reserved || Player graphics source bank, specified in the low byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_Enable&amp;lt;/code&amp;gt; || 1 byte || Zero disables player palette management through this system; nonzero enables it.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_Addr&amp;lt;/code&amp;gt; || 2 bytes || Player palette source address.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_BNK&amp;lt;/code&amp;gt; || 1 byte || Palette bank. When zero, the routine uses the game&#039;s player palette address.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_CustomPlayer&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_Dynamic_Player_LastCustomPlayer&amp;lt;/code&amp;gt; || 1 byte each || Reserved to identify current and previous custom players. Initialized to 0 and &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;; currently do not select character graphics by themselves.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_VRAMEnable&amp;lt;/code&amp;gt; || 1 byte || Zero disables Yoshi graphics loading through this system; nonzero enables it.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_Addr&amp;lt;/code&amp;gt; || 2 bytes || Yoshi graphics start address within the bank.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_BNK&amp;lt;/code&amp;gt; || 1 byte || Yoshi graphics source bank.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Drawing and sprite variables ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Drawing_InitialIndexHighPriority&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_Drawing_InitialIndexLowPriority&amp;lt;/code&amp;gt; each occupy 1 byte and track available drawing positions for high- and low-priority sprites. &amp;lt;code&amp;gt;DX_Drawing_OAMMap&amp;lt;/code&amp;gt; occupies 128 bytes and helps organize drawn tiles. These variables are used on LoROM; SA-1 uses its corresponding drawing management.&lt;br /&gt;
&lt;br /&gt;
Individual sprite variables are defined in &amp;lt;code&amp;gt;DynamicXSpritesTables.asm&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; let all three types use the same names:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Sprite name !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt; || Desired pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt; || Last obtained pose available for drawing. Initialize to &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; || Cache entry tracking the graphics&#039; location. Initialize to &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt; || Overall flip, additional pose flip, and effective drawing flip.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; || Assigned palette: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; for 8, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; for 9, through &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; for F. Initialize to &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; for dynamic assignment.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt; options: global effect and palette or palette-group selection.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; || Assignment mode: automatic, manual, or manual without uploading colors.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt; || Sprite variant and last variant processed for its palette. Initialize &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen,x&amp;lt;/code&amp;gt; || Distances that allow drawing when the sprite&#039;s position is offscreen but some of its pose may remain visible.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SafeFrameLowByte,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!SafeFrameHighByte,x&amp;lt;/code&amp;gt; || Last frame a pose request was attempted, preventing repeated work in the same frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AnimationIndex,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AnimationPoseIndex,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AnimationTimer,x&amp;lt;/code&amp;gt; || Available variables for the animation, current step, and timer. The resource&#039;s code decides how to use them.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!State,x&amp;lt;/code&amp;gt; || Resource state or behavior variable.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each variable occupies 1 byte per sprite. Normal sprites have &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; entries, cluster sprites 20, and extended sprites 10. Do not use &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; as the cluster or extended entry count.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; mark the start of these table areas. They are not free memory for storing your own data over sprite variables.&lt;br /&gt;
&lt;br /&gt;
=== Fixed defines ===&lt;br /&gt;
&lt;br /&gt;
These names represent known configurations and addresses, not variables that change during gameplay.&lt;br /&gt;
&lt;br /&gt;
==== LoROM and SA-1 compatibility ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; detects the ROM type and selects the corresponding values. Use these names to support both types.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! LoROM !! SA-1 !! Use&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!sa1&amp;lt;/code&amp;gt; || 0 || 1 || Select different code by ROM type.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!dp&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3000&amp;lt;/code&amp;gt; || Direct-page address adjustment.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!addr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; || RAM address adjustment where required, for example &amp;lt;code&amp;gt;$0100|!addr&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!rom&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$800000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$000000&amp;lt;/code&amp;gt; || Adjustment for original game code addresses.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; (12) || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; (22) || Normal sprite slot count.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MultiplicationResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4216&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2306&amp;lt;/code&amp;gt; || Multiplication result address.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DivisionResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4214&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2306&amp;lt;/code&amp;gt; || Division quotient address.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RemainderResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4216&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2308&amp;lt;/code&amp;gt; || Division remainder address.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Other variable-placement defines are &amp;lt;code&amp;gt;!normalBnk&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalCopyBNK&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt;. Normally, use each &amp;lt;code&amp;gt;DX_...&amp;lt;/code&amp;gt; variable&#039;s name rather than calculate its address from these values.&lt;br /&gt;
&lt;br /&gt;
==== Graphics addresses in VRAM ====&lt;br /&gt;
&lt;br /&gt;
These defines specify transfer destinations without numeric addresses. Each family has lines 0 through 7; replace N with the line number.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Family !! Line 0 !! Increment per line !! Example&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG1LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG1Line1 = $0100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG2LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG2Line1 = $0900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG1LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG1Line1 = $1100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG3LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG3Line1 = $1900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG2LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG2Line1 = $2100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG3LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG3Line1 = $2900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LG1LineN&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;!LG4LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4400&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4800&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4C00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!LG1Line1 = $4080&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SP1LineN&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;!SP4LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6800&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$7000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$7800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!SP4Line1 = $7900&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Layer1Tilemap = $3000&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!Layer2Tilemap = $3800&amp;lt;/code&amp;gt; are the usual Layer 1 and Layer 2 tilemap addresses. VRAM addresses here use 2-byte words, as do the transfer macros.&lt;br /&gt;
&lt;br /&gt;
==== Space configurations for dynamic poses ====&lt;br /&gt;
&lt;br /&gt;
Pass &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt; defines to &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt;. Each name identifies the allowed graphics areas. &amp;lt;code&amp;gt;FirstHalf&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;SecondHalf&amp;lt;/code&amp;gt; identify half-areas. Names containing &amp;lt;code&amp;gt;WithPlayer&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;WithDSX&amp;lt;/code&amp;gt; are intended for those configurations.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Value !! Define&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$09&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP1WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP11WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3ndSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2andSP34&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$11&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$13&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$15&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3ndSP4WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$17&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2andSP34WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$19&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithPlayerAndDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithPlayerAndDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Spell these names exactly as published in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, including names such as &amp;lt;code&amp;gt;SecondHalfSSP4&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;SP11WithPlayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Other constants ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! Value or use&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AN2Buffer1&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AN2Buffer2&amp;lt;/code&amp;gt; || Animation data addresses &amp;lt;code&amp;gt;$7EC100&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$7EAD00&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt;, the usual GFX32 buffer address.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PlayerPaletteColor2To5&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$00B280&amp;lt;/code&amp;gt;, player palette colors 2–5.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PlayerBasePalette&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$00B2C8&amp;lt;/code&amp;gt;, player base palette data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; || Both are 64 in the current template. Reserve transfer tables; they are not the per-frame byte limit.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Installation options such as &amp;lt;code&amp;gt;!DynamicPoses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DrawingSystem&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!GraphicsChange&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalettesChange&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalettesEffects&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PlayerFeatures&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!YoshiFeatures&amp;lt;/code&amp;gt; come from &amp;lt;code&amp;gt;Options.asm&amp;lt;/code&amp;gt;. They identify installed features and are not changed at runtime.&lt;br /&gt;
&lt;br /&gt;
=== Generated defines ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme creates these defines during resource installation and adds them to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Use their names rather than copied numeric values, because IDs, addresses, and sizes may change when resources are added or modified.&lt;br /&gt;
&lt;br /&gt;
Names use PascalCase normalization: remove spaces, underscores, hyphens, and other separators and capitalize each word&#039;s first letter. For example, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;my-sprite&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;my sprite&amp;lt;/code&amp;gt; become &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Other existing capitalization is preserved. When unsure, copy the exact name from &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Dynamic poses and drawing poses ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Family or example !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; || ID of pose graphics declared in DynamicInfo. Used to request loading with &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseMySprite000&amp;lt;/code&amp;gt; || ROM address of those graphics.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseMySprite000Size&amp;lt;/code&amp;gt; || Graphics data size in bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; || DrawInfo pose ID. Used for drawing with &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;DrawStatic&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; || Horizontal distance calculated from DrawInfo to determine when the sprite is no longer visible.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; || Vertical distance for the same check.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Dynamic IDs choose which graphics to load; drawing IDs choose how tiles form the pose. These are different values. Do not substitute a &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; for a &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Palettes and effects ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Family or example !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteIDMyPalette&amp;lt;/code&amp;gt; || ID of a palette declared in DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; || ROM address of its colors.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyPaletteSize&amp;lt;/code&amp;gt; || Palette size in bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; || Start of that DynamicInfo&#039;s palette list. Passed to &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; and its variants.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; || Effect ID from &amp;lt;code&amp;gt;my_effect.paleffect&amp;lt;/code&amp;gt;. The suffix is the effect&#039;s index within the file; global IDs start at 1.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyTargetRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PaletteMyTargetHSL&amp;lt;/code&amp;gt; || ROM address of a target palette converted for an RGB/HSL transition. Generated when an effect needs that palette.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyTargetRGBSize&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PaletteMyTargetHSLSize&amp;lt;/code&amp;gt; || Converted palette sizes in bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example names follow the same normalization: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. Defines are generated during installation and stored in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== General resources and buffers ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Family or example !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt; || General resource ID from DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt; || Resource ROM address.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt; || Resource size in bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferIDMyBuffer&amp;lt;/code&amp;gt; || ID of a tool-inserted buffer.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferMyBuffer&amp;lt;/code&amp;gt; || ROM address of the inserted buffer, not temporary RAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferMyBufferSize&amp;lt;/code&amp;gt; || Buffer size in bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Names depend on installed resources and use the same normalization: &amp;lt;code&amp;gt;my_resource&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyResource&amp;lt;/code&amp;gt;. Check &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; for your installation&#039;s names and values.&lt;br /&gt;
&lt;br /&gt;
==== Generated counts and tables ====&lt;br /&gt;
&lt;br /&gt;
These defines expose counts and tables generated during installation. Normal sprites usually need only the individual IDs in the tables above.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfDynamicPoses&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfPoses&amp;lt;/code&amp;gt; || Installed dynamic pose count and drawing pose count, respectively.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfPalettes&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfResources&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfBuffers&amp;lt;/code&amp;gt; || Inserted normal palette, general resource, and buffer counts.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfPaletteEffects&amp;lt;/code&amp;gt; || Value used to size effect tables. Generation includes space for ID 0; do not interpret this as a single &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; file&#039;s effect count.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteTableSize&amp;lt;/code&amp;gt; || Total entries in DynamicInfo palette lists.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteIDTables&amp;lt;/code&amp;gt; || Address of those lists&#039; ID table.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAddrTables&amp;lt;/code&amp;gt; || Address of the table containing their color ROM addresses.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsTypes&amp;lt;/code&amp;gt; || Table of installed effect types.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsChannels1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsChannels2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsChannels3&amp;lt;/code&amp;gt; || Tables of each effect&#039;s color values.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsRatios1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsRatios2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsRatios3&amp;lt;/code&amp;gt; || Ratio tables controlling each change&#039;s strength.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferTable&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteTables&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsTable&amp;lt;/code&amp;gt; || Table addresses published by the patch.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Routine defines ===&lt;br /&gt;
&lt;br /&gt;
These defines represent system calls, not data variables. This table helps locate them; their use is explained in the routine and macro sections.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define or family !! Use&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AllowedGameMode&amp;lt;/code&amp;gt; || Checks whether the current game mode permits the corresponding operations.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; || Selects VRAM regions available for dynamic poses.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; || Requests a pose by ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; || Prepares pose graphics transfers to VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SetPropertyAndOffset&amp;lt;/code&amp;gt; || Gets a dynamic pose&#039;s graphics location and properties for drawing.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Draw&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!Draw_Return&amp;lt;/code&amp;gt; || Drawing routine entry and return point.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RemapOamTile&amp;lt;/code&amp;gt; || Adjusts tile numbers for the actual dynamic graphics location.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!IsValid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!XIsValid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!YIsValid&amp;lt;/code&amp;gt; || Drawing checks to determine tile visibility.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AssignPalette&amp;lt;/code&amp;gt; || Selects a palette destination according to assignment mode.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LoadPaletteOnBuffer&amp;lt;/code&amp;gt; || Loads palette data into a working buffer.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SetRGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!SetHSLBase&amp;lt;/code&amp;gt; || Prepares colors for RGB/HSL effects.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RGBToHSL&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!HSLToRGB&amp;lt;/code&amp;gt; || Converts between color spaces.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RGBMerge&amp;lt;/code&amp;gt; || Converts separate RGB colors to SNES palette format.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Mix...&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!MixAndMerge...&amp;lt;/code&amp;gt; || Changes one or more color components.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalTransitionRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PalTransitionHSL&amp;lt;/code&amp;gt; || Calculates a palette transition.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalTransitionAndMergeRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PalTransitionAndMergeHSL&amp;lt;/code&amp;gt; || Calculates a transition and produces SNES-format colors.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DoEffect&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!DoEffectAndMerge&amp;lt;/code&amp;gt; || Applies an effect by ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalFunctionRGB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalFunctionHSL&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; variants || Reserved names for color functions not implemented yet.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Routines&amp;lt;/code&amp;gt; is the table address used to obtain these calls. You do not need to calculate offsets to use published defines.&lt;br /&gt;
&lt;br /&gt;
== CPU state and temporary memory ==&lt;br /&gt;
&lt;br /&gt;
Each call requires the register widths specified in its inputs. A register can return in 8-bit mode while losing its previous value: &#039;&#039;&#039;width and contents are different things&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Unless an entry states otherwise, these rules apply throughout this article:&lt;br /&gt;
&lt;br /&gt;
* Run in native mode with decimal mode disabled. The system&#039;s arithmetic uses binary numbers.&lt;br /&gt;
* &#039;&#039;&#039;Direct page D:&#039;&#039;&#039; &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; on LoROM and &amp;lt;code&amp;gt;$3000&amp;lt;/code&amp;gt; in the usual SA-1 Pack context. Short addresses such as &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; are relative to that base. Calls do not prepare or change D for you.&lt;br /&gt;
* &#039;&#039;&#039;Data bank DBR:&#039;&#039;&#039; must allow access to the RAM mirrors and hardware registers used by the call. The usual context uses banks with these mirrors, such as &amp;lt;code&amp;gt;$00-$3F&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;$80-$BF&amp;lt;/code&amp;gt;. If an operand reads a table through a 16-bit address, DBR must also allow access to that table. A 24-bit pointer carries its own bank. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; has a specific DBR requirement explained in its entry.&lt;br /&gt;
* Calls preserve DBR and D. Some change DBR temporarily and restore it before returning. This does not make every input bank valid.&lt;br /&gt;
* &#039;&#039;&#039;Flags:&#039;&#039;&#039; only use explicitly documented output flags. Do not assume N, Z, V, or carry retain their old values. A and X/Y width changes are specified per call.&lt;br /&gt;
* &#039;&#039;&#039;Temporary memory:&#039;&#039;&#039; listed scratch may be overwritten on success or failure. Save values needed afterward elsewhere. Outputs are valid only under the stated conditions.&lt;br /&gt;
* &#039;&#039;&#039;Stack:&#039;&#039;&#039; calls remove their own temporary stack data. Match your own pushes and pulls at the same register width and respect the routine or macro&#039;s return type.&lt;br /&gt;
&lt;br /&gt;
To preserve a register, save it before the call and restore it afterward at the same width. Check returned carry before another operation changes it; restoring P with &amp;lt;code&amp;gt;PLP&amp;lt;/code&amp;gt; also replaces that carry.&lt;br /&gt;
&lt;br /&gt;
== Sprite routines ==&lt;br /&gt;
&lt;br /&gt;
These routines check whether a sprite should be drawn, load its graphics, and manage its palettes. Include the appropriate defines file first: &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt;. Its path is relative to the sprite ASM.&lt;br /&gt;
&lt;br /&gt;
DBR, D, flag, and stack requirements are explained in [[#CPU_state_and_temporary_memory|CPU state and temporary memory]]. The table below distinguishes register widths from preserved values.&lt;br /&gt;
&lt;br /&gt;
Write calls such as &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; directly, as in the examples. Do not prefix them with &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;. Unless stated otherwise, X must contain the sprite slot index.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sprite call registers and scratch&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enter with 8-bit X and Y. A&#039;s width depends on the call:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Call !! A on entry !! Registers on return !! Scratch potentially overwritten&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;&lt;br /&gt;
| 8 bits.&lt;br /&gt;
| A changes and returns in 8-bit mode. X and Y retain their values and widths.&lt;br /&gt;
| No scratch; modifies the Dynamic Xtreme tables described in its entry.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;&lt;br /&gt;
| 16 bits with &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; enabled; 8 bits when disabled, without using the table offset.&lt;br /&gt;
| A and Y may change. X is reloaded from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; when used internally. The no-upload variant returns information in Y. All three return in 8-bit mode.&lt;br /&gt;
| &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$65-$67&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;$D5&amp;lt;/code&amp;gt;, depending on the path. With effects, may also use the effect temporaries listed below.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;&lt;br /&gt;
| 16 bits.&lt;br /&gt;
| A and Y may change. X is restored from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. All three return in 8-bit mode.&lt;br /&gt;
| &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$47-$51&amp;lt;/code&amp;gt; when preparing a new load.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt;&lt;br /&gt;
| 16 bits.&lt;br /&gt;
| A and Y may change. When drawing, X is restored from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; if no valid pose exists, input X is retained. All three return in 8-bit mode.&lt;br /&gt;
| &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$45-$4F&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;. Additional offsets also use &amp;lt;code&amp;gt;$8B-$8C&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;&lt;br /&gt;
| 8 bits.&lt;br /&gt;
| A and Y may change. X is restored from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. All three return in 8-bit mode.&lt;br /&gt;
| &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; and temporaries used for color loading; effect temporaries when applicable.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; and its HSL variant&lt;br /&gt;
| 16 bits.&lt;br /&gt;
| A and Y may change. X takes a palette on entry but contains &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; on return. All three return in 8-bit mode.&lt;br /&gt;
| Effect temporaries, &amp;lt;code&amp;gt;$05-$06&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;$F0-$F3&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
PIXI maintains &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; as the current sprite index. If you temporarily change X, calls restoring that index do not necessarily preserve the X value you supplied. After effect concatenation, X identifies the sprite again, not its palette. PIXI aliases call their shared routines and continue at the next instruction; the examples&#039; &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; belongs to the sprite&#039;s own routine.&lt;br /&gt;
&lt;br /&gt;
=== RenderBox ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; checks whether the sprite is on screen or close enough to its edges to keep drawing. Use it at the start of the main routine to choose between core logic only (short routine) or graphics loading, palette management, and drawing as well (long routine).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routine used by sprite type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Normal sprite: &amp;lt;code&amp;gt;%DXNormalRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* X: sprite index.&lt;br /&gt;
* &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen,x&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen,x&amp;lt;/code&amp;gt;: allowed horizontal and vertical distances outside the screen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry set: the sprite is on screen or within the allowed offscreen distance; run the long routine.&lt;br /&gt;
* Carry clear: the sprite is too far offscreen to draw; run the short routine.&lt;br /&gt;
&lt;br /&gt;
When too far offscreen, sets &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, indicating that palette and pose must be obtained again when it returns. Also combines &amp;lt;code&amp;gt;!GlobalFlip&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!LocalFlip&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt;. For normal sprites, updates horizontal and vertical offscreen flags as well.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
print &amp;quot;INIT &amp;quot;,pc&lt;br /&gt;
    LDA.b #!RenderBoxXDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderXDistanceOutOfScreen,x&lt;br /&gt;
    LDA.b #!RenderBoxYDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderYDistanceOutOfScreen,x&lt;br /&gt;
    ; Put the rest of the sprite initialization here&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
SpriteCode:&lt;br /&gt;
    !RenderBox&lt;br /&gt;
    BCS .LongRoutine&lt;br /&gt;
&lt;br /&gt;
.ShortRoutine&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    %SubOffScreen()&lt;br /&gt;
    ; Put your sprite&#039;s logic here&lt;br /&gt;
RTS&lt;br /&gt;
&lt;br /&gt;
.LongRoutine&lt;br /&gt;
    ; Put palette management, pose loading, drawing,&lt;br /&gt;
    ; and your sprite&#039;s logic here&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The example&#039;s &amp;lt;code&amp;gt;%SubOffScreen()&amp;lt;/code&amp;gt; is for normal sprites and takes A from 0 to 7 to select offscreen removal settings. It uses the usual value, 0. Calling it in the short routine is recommended; it is redundant in the long routine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; are generated from DrawInfo and stored in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Resource names use PascalCase: remove spaces, underscores, and hyphens and capitalize each word&#039;s first letter. For example, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. With multiple DrawInfo files, use the largest horizontal and vertical distances among them.&lt;br /&gt;
&lt;br /&gt;
=== PaletteAssignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; selects a DynamicInfo palette using &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;, assigns it to one of sprite palettes 8–F, and loads its colors when needed. If already assigned, resets its protection timer to 2 so another resource cannot replace it. Call every long-routine frame; this does not mean colors are uploaded every time.&lt;br /&gt;
&lt;br /&gt;
If bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; of &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; is set (&amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;), it also processes the corresponding global palette effects. Otherwise the palette is excluded from the global effect.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;How the palette is selected&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; selects an entry from DynamicInfo&#039;s palette list: 0 for the first, 1 for the second, and so on. For a list containing red and blue palettes, versions 0 and 1 select those colors. Sprite behavior may also depend on this variable; palette management only uses it to select colors.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; determines which sprite palette may be used and whether it receives the global effect. Format: &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt;: 0 excludes the palette from the global effect; 1 allows it.&lt;br /&gt;
* &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt;: in manual mode, selects palette 8–F. &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; selects 8, &amp;lt;code&amp;gt;001&amp;lt;/code&amp;gt; selects 9, through &amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt; for F.&lt;br /&gt;
* In automatic mode, &amp;lt;code&amp;gt;PPP = 000&amp;lt;/code&amp;gt; allows all eight palettes. Nonzero &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; limits the search to 8–B; &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; limits it to C–F.&lt;br /&gt;
* The low four bits are unused by these options.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; determines who chooses the destination and whether colors are uploaded. Format: &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 00&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;): automatic. Dynamic Xtreme chooses an allowed palette and loads DynamicInfo&#039;s colors.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 01&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;): manual. Uses the palette specified by &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; and loads DynamicInfo&#039;s colors.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 10&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;): manual without upload. Uses the specified palette with the level&#039;s existing colors.&lt;br /&gt;
&lt;br /&gt;
For normal sprites, &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;!ExtraProp2,x&amp;lt;/code&amp;gt;. Commonly use &amp;lt;code&amp;gt;EPPPVVVV&amp;lt;/code&amp;gt; in Extra Byte 1 and copy its low four bits to &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; in INIT, selecting the version through Lunar Magic. For cluster and extended sprites, the spawning code must set these variables.&lt;br /&gt;
&lt;br /&gt;
For example, manual &amp;lt;code&amp;gt;!PaletteOption,x = $A0&amp;lt;/code&amp;gt; uses palette A and allows the global effect. With &amp;lt;code&amp;gt;!Version,x = 1&amp;lt;/code&amp;gt;, it loads the second palette from DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routine used by sprite type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Normal sprite: &amp;lt;code&amp;gt;%DXNormalPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 16-bit A: &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; for the DynamicInfo containing the palettes.&lt;br /&gt;
* X: sprite index.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;: palette index in the table.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: last processed version, compared with &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; to detect changes. Initialize to &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;: palette selection and participation in the global effect.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt;: automatic, manual, or manual-without-upload assignment.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry set: the sprite can be drawn with the assigned palette.&lt;br /&gt;
* Carry clear: the sprite has no palette ready for drawing yet.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: assigned palette, increasing by two from &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; for palettes 8–F.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: updated to &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; when the new assignment is processed.&lt;br /&gt;
* A, X, and Y return in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignment&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; is generated from DynamicInfo and stored in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. The resource name uses PascalCase normalization: remove separators and capitalize each word&#039;s first letter, so &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== PaletteAssignmentNoUpload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; selects a palette like &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; but leaves the color upload pending. Use it to modify the palette first, for example by applying a local effect combined with the global effect. If already assigned, resets its protection timer to 2 against replacement.&lt;br /&gt;
&lt;br /&gt;
Bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; of &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;) also controls global effects. This variant prepares assignment and the base palette; a subsequent routine such as &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt; completes the effects and upload.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; selects the DynamicInfo palette: 0 for the first, 1 for the second. &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; uses &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: E enables the global effect, and PPP selects palette 8–F manually or a search group automatically. In automatic mode, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; allows all, nonzero &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; allows 8–B, and &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; allows C–F.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; uses &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; selects the destination automatically, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; uses PPP, and &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; uses existing level colors. To prepare a palette for a later local effect, use a mode that reads DynamicInfo colors: automatic or manual with upload.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routine used by sprite type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Normal sprite: &amp;lt;code&amp;gt;%DXNormalPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 16-bit A: &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; for the DynamicInfo containing the palettes.&lt;br /&gt;
* X: sprite index.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt;: same options as &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: last processed version, compared with &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; to detect changes. Initialize to &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry set: a palette is assigned; clear if one could not be obtained.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: assigned palette.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: updated to &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; when the new assignment is processed.&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: ID of the selected DynamicInfo palette when using a mode that loads its colors.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: base palette ROM address.&lt;br /&gt;
* Y = 1: palette newly assigned and effect must be calculated; Y = 0: no recalculation needed due to a new assignment. Pass this value to the concatenation routine.&lt;br /&gt;
* A, X, and Y return in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    ; Prepare and concatenate the effect here.&lt;br /&gt;
    ; Preserve Y and the $02-$04 address for that call.&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; identifies the chosen DynamicInfo palette; &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; identifies the sprite palette 8–F used for drawing. &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; is prepared only when the routine reads DynamicInfo. Do not treat it as output in manual-without-upload mode, with palette changes disabled, or when the current game mode does not process the call.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; is generated from DynamicInfo and stored in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. PascalCase normalization removes separators: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Upload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; makes the graphics for the sprite&#039;s current pose available for drawing. It selects the pose by adding &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt; to the dynamic pose ID in A. If the graphics are already in VRAM, it updates their last-use record to protect them from replacement. Otherwise, it requests an upload. Call it every frame in the long routine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routine used by sprite type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Normal sprite: &amp;lt;code&amp;gt;%DXNormalUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 16-bit A: base dynamic pose ID.&lt;br /&gt;
* X: sprite index.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt;: index added to the base ID.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt;: flip settings combined when drawing the pose.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry set: the sprite has a pose it can draw. This may be the requested pose or the previous one if the new pose could not be uploaded yet.&lt;br /&gt;
* Carry clear: the sprite does not have a pose it can draw yet.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt;: state of the pose available for drawing.&lt;br /&gt;
* A, X, and Y return in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    !Upload&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; is generated from the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized to PascalCase: separators are removed and each word starts with a capital letter, as in &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== UploadWithoutPoseOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; requests the exact dynamic pose ID in A, without adding &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;. Like &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, it reuses graphics already in VRAM and can keep the previous pose available until the new one can be uploaded.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routine used by sprite type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Normal sprite: &amp;lt;code&amp;gt;%DXNormalUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedUploadWithoutPoseOffset()&amp;lt;/code&amp;gt; exists, but &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; currently does not provide the &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; alias.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 16-bit A: exact dynamic pose ID.&lt;br /&gt;
* X: sprite index.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt;: sprite flip settings.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry set: the sprite has a pose it can draw. Carry clear: no pose is available yet.&lt;br /&gt;
* Stores the pose available for drawing in &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt; and its graphics location in &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;, just like &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A, X, and Y return in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite003&lt;br /&gt;
    !UploadWithoutPoseOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite003&amp;lt;/code&amp;gt; is generated from the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names use PascalCase, with separators removed: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== DXDraw ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; draws a pose using the dynamic graphics available to the sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routine used by sprite type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Normal sprite: &amp;lt;code&amp;gt;%DXNormalDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 16-bit A: drawing pose ID.&lt;br /&gt;
* X: sprite index.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;): additional properties in &amp;lt;code&amp;gt;YXCC----&amp;lt;/code&amp;gt; format.&lt;br /&gt;
* &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;): maximum tile priority; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; highest, &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; high, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; the sprite type&#039;s own priority, and &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; lowest.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;: palette, flip settings, and location of the available graphics.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Draws the pose on screen. If &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, nothing is drawn. A, X, and Y return in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDraw&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, the poses must appear in the same order in the DrawInfo and DynamicInfo. &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; identifies the pose that can actually be drawn: if the new pose could not be uploaded yet, the previous one is drawn instead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; is generated from the DrawInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Resource and pose names are normalized to PascalCase by removing separators, as in &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. This drawing ID is separate from the DynamicInfo&#039;s &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; IDs.&lt;br /&gt;
&lt;br /&gt;
=== DXDrawWithOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; draws the pose a few pixels to the right, left, above, or below the sprite&#039;s position. This only changes where the pose is drawn; movement and collision still use the sprite&#039;s original position.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routine used by sprite type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Normal sprite: &amp;lt;code&amp;gt;%DXNormalDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* The same inputs as &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;): signed 8-bit horizontal offset.&lt;br /&gt;
* &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;): signed 8-bit vertical offset.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Draws the pose like &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;, with the specified offsets added. A positive &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; moves the drawing to the right, and a positive &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; moves it down. Negative values move it left or up.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$08&lt;br /&gt;
    STA !XOffsetParam&lt;br /&gt;
    LDA #$F8&lt;br /&gt;
    STA !YOffsetParam&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDrawWithOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The example draws the pose 8 pixels to the right and 8 pixels up. &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; is generated from the DrawInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; names are normalized to PascalCase by removing separators, as in &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ReplacePalette ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt; changes the colors of the sprite&#039;s assigned palette without changing its assignment ID. For example, it can replace the normal palette during a special state. If other sprites share that palette, their colors change too. Call it when the colors need to change; calling it every frame makes the system prepare the palette and its effects again each time.&lt;br /&gt;
&lt;br /&gt;
It is commonly used after &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;: assign the palette without uploading its colors, then replace them with the colors you want. Before calling &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, put the address of the new colors in &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routine used by sprite type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Normal sprite: &amp;lt;code&amp;gt;%DXNormalReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* X: sprite index.&lt;br /&gt;
* A in 8-bit mode.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: ROM address of the new palette in BGR555 format.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: the assigned palette.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;: whether the palette is affected by the global effect.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry set: the palette is ready for drawing. If the new colors are not ready yet, the previous colors remain available.&lt;br /&gt;
* Carry clear: the palette has no colors ready for drawing yet.&lt;br /&gt;
&lt;br /&gt;
Keeps the same palette ID and requests a change to its colors. When marking the effect for recalculation, it uses &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; if no colors have ever been ready for drawing, or &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; if the previous colors can still be used while the new ones are prepared.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ReplaceSpritePalette:&lt;br /&gt;
    ; Run when an assigned palette needs new colors.&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;8&lt;br /&gt;
    STA $03&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
    !ReplacePalette&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyAlternatePalette&amp;lt;/code&amp;gt; is the address of a palette inserted from the resources declared in a DynamicInfo. It is written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name is normalized to PascalCase: &amp;lt;code&amp;gt;my_alternate_palette&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyAlternatePalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ConcatenateRGBPaletteEffectToGlobal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; lets the sprite&#039;s palette use its own RGB effect while still being affected by the global effect. It applies the local effect, such as &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, first, then applies the global effect to that result. Call it after &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, which prepares the original palette.&lt;br /&gt;
&lt;br /&gt;
The usual sequence is to assign the palette with &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, check that carry is set, then call this routine to apply the effects and finish uploading the colors.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routine used by sprite type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Normal sprite: &amp;lt;code&amp;gt;%DXNormalConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 16-bit A: local RGB effect ID.&lt;br /&gt;
* 8-bit X: copy the value of &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; here using &amp;lt;code&amp;gt;LDA !Palette,x&amp;lt;/code&amp;gt; followed by &amp;lt;code&amp;gt;TAX&amp;lt;/code&amp;gt;, as shown in the example.&lt;br /&gt;
* 8-bit Y: keep the value returned by &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;. A value of 1 forces the effect to be recalculated; 0 allows the previous result to be reused if nothing has changed.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: BGR555 base palette address prepared by palette assignment.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;: the &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; bit must be set to combine the local effect with the global effect.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry set: the palette can be used for drawing. If the new effect is not ready yet, the previous result remains in use.&lt;br /&gt;
* Carry clear: the palette has no colors ready for drawing yet.&lt;br /&gt;
* A, X, and Y return in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyRGBEffect0&lt;br /&gt;
    !ConcatenateRGBPaletteEffectToGlobal&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; is generated from the DynamicInfo, and &amp;lt;code&amp;gt;!PaletteEffectIDMyRGBEffect0&amp;lt;/code&amp;gt; from a &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; file. Both are written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized to PascalCase by removing separators, as in &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. If you use Y to select an effect from a table, save it with &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; and restore it with &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; before calling the concatenation routine.&lt;br /&gt;
&lt;br /&gt;
=== ConcatenateHSLPaletteEffectToGlobal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt; lets the sprite&#039;s palette use its own HSL effect, such as &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, while still being affected by the global effect. It applies the local effect first, followed by the global effect. Call it after &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, which prepares the original palette.&lt;br /&gt;
&lt;br /&gt;
The usual sequence is to assign the palette with &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, check that carry is set, then call this routine to apply the effects and finish uploading the colors.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routine used by sprite type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Normal sprite: &amp;lt;code&amp;gt;%DXNormalConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 16-bit A: local HSL effect ID.&lt;br /&gt;
* 8-bit X: copy the value of &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; here using &amp;lt;code&amp;gt;LDA !Palette,x&amp;lt;/code&amp;gt; followed by &amp;lt;code&amp;gt;TAX&amp;lt;/code&amp;gt;, as shown in the example.&lt;br /&gt;
* 8-bit Y: keep the value returned by &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;. A value of 1 forces the effect to be recalculated; 0 allows the previous result to be reused if nothing has changed.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: BGR555 base palette address prepared by palette assignment.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;: the &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; bit must be set to combine the local effect with the global effect.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry set: the palette can be used for drawing. If the new effect is not ready yet, the previous result remains in use.&lt;br /&gt;
* Carry clear: the palette has no colors ready for drawing yet.&lt;br /&gt;
* A, X, and Y return in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyHSLEffect0&lt;br /&gt;
    !ConcatenateHSLPaletteEffectToGlobal&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; is generated from the DynamicInfo, and &amp;lt;code&amp;gt;!PaletteEffectIDMyHSLEffect0&amp;lt;/code&amp;gt; from a &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; file. Both are written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized to PascalCase: separators are removed and each word starts with a capital letter. Save and restore Y with &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; if you temporarily use it to select an effect.&lt;br /&gt;
&lt;br /&gt;
Both concatenation variants handle the required conversions when the local and global effects use different color spaces. See [[Dynamic_Xtreme_files_and_formats#Effect_types|Effect types]] to find out which effects use RGB or HSL.&lt;br /&gt;
&lt;br /&gt;
== General Routines and Macros ==&lt;br /&gt;
&lt;br /&gt;
These routines and macros let sprites, UberASM, and other code use Dynamic Xtreme&#039;s systems. Macro arguments specify the variables and values to use. If an argument contains a comma, such as &amp;lt;code&amp;gt;!NormalPoseIndex,x&amp;lt;/code&amp;gt;, put it in quotation marks so Asar reads it as a single argument. Use &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; for immediate values, such as &amp;lt;code&amp;gt;#$04&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The rules for [[#CPU_state_and_temporary_memory|DBR, direct page, flags, and the stack]] also apply here. Each family&#039;s calling requirements explain which registers and temporary memory you must save if you need to preserve them.&lt;br /&gt;
&lt;br /&gt;
=== Calls and returns at a glance ===&lt;br /&gt;
&lt;br /&gt;
Some macros include the return instruction that ends the routine containing them. In those cases, code written after the macro does not run as a continuation of that routine.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Call or family !! Included return !! Usage&lt;br /&gt;
|-&lt;br /&gt;
| Sprite aliases: &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, and the other aliases in this category.&lt;br /&gt;
| The call returns and execution continues after the alias.&lt;br /&gt;
| Write the alias directly, without &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;. Your routine still needs its own return instruction.&lt;br /&gt;
|-&lt;br /&gt;
| [[#GeneralUpload|GeneralUpload]], [[#Upload_(general_macro)|Upload (general macro)]], and [[#StandardSpriteUpload|StandardSpriteUpload]].&lt;br /&gt;
| &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Place the macro at the end of a routine called with &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Draw|Draw]], [[#StandardSpriteDraw|StandardSpriteDraw]], and [[#DrawStatic|DrawStatic]].&lt;br /&gt;
| &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Place the macro at the end of a routine called with &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#PaletteAssignment_(general_macro)|PaletteAssignment]], [[#PaletteAssignmentNoUpload_(general_macro)|PaletteAssignmentNoUpload]], [[#StandardSpritePaletteAssignment|StandardSpritePaletteAssignment]], and [[#StandardSpritePaletteAssignmentNoUpload|StandardSpritePaletteAssignmentNoUpload]].&lt;br /&gt;
| &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Place the macro at the end of a routine called with &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| The general macro versions of [[#ReplacePalette_(general_macro)|ReplacePalette]] and [[#Combining_a_local_effect_with_the_global_effect|ConcatenateRGBPaletteEffectToGlobal and ConcatenateHSLPaletteEffectToGlobal]].&lt;br /&gt;
| &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Place the macro at the end of a routine called with &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#LoadPaletteIDAndAddress|LoadPaletteIDAndAddress]] and [[#DefineDynamicSpaceConfig|DefineDynamicSpaceConfig]].&lt;br /&gt;
| None: execution continues after the macro.&lt;br /&gt;
| You can write more code after the macro. Your routine needs its own return instruction.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Uploading_colors_with_TransferPalette|TransferPaletteFromAddress, FromPointer, FromTable, Resource, and ResourceWithLength]].&lt;br /&gt;
| None: execution continues after the macro.&lt;br /&gt;
| Check carry after the macro, then continue or return according to the result.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Palette_effects|Base preparation, mixing, transition, DoEffect, and conversion]] macros, including their &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; variants.&lt;br /&gt;
| None: execution continues after the macro.&lt;br /&gt;
| You can chain more operations after the macro. The two concatenation macros are the exceptions listed above.&lt;br /&gt;
|-&lt;br /&gt;
| [[#PPU|VRAM and CGRAM transfer]] macros, including &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; variants, and [[#Math|math]] macros.&lt;br /&gt;
| None: execution continues after the macro.&lt;br /&gt;
| Your routine needs its own return instruction.&lt;br /&gt;
|-&lt;br /&gt;
| Patch routines [[#DynamicPoseSpaceConfig|DynamicPoseSpaceConfig]], [[#TakeDynamicRequest|TakeDynamicRequest]], and [[#DynamicRoutine|DynamicRoutine]].&lt;br /&gt;
| The called routine returns with &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Use &amp;lt;code&amp;gt;JSL !NombreDeLaRutina&amp;lt;/code&amp;gt;. On return, execution resumes at the instruction after &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;; your routine still needs its own return instruction.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For example, a routine containing &amp;lt;code&amp;gt;%Upload(...)&amp;lt;/code&amp;gt; is called with &amp;lt;code&amp;gt;JSR PoseManagement&amp;lt;/code&amp;gt; and ends with the macro&#039;s own &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;. A routine containing &amp;lt;code&amp;gt;%PaletteAssignment(...)&amp;lt;/code&amp;gt; is called with &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt; and ends with its &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; alias works differently: it calls a shared PIXI routine and allows execution to continue afterward, rather than expanding &amp;lt;code&amp;gt;%Upload(...)&amp;lt;/code&amp;gt; directly.&lt;br /&gt;
&lt;br /&gt;
=== Dynamic poses ===&lt;br /&gt;
&lt;br /&gt;
==== DynamicPoseSpaceConfig ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; enter with A, X, and Y in 8-bit mode. Modifies A and X; preserves Y and register sizes. Uses no scratch memory. Saves and restores DBR around configuration selection. Does not return a result in carry. Called with &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;; returns with &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; selects the parts of graphics memory (VRAM) that Dynamic Xtreme can use for dynamic poses. It is normally called from UberASM&#039;s &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; when entering a level.&lt;br /&gt;
&lt;br /&gt;
The available configurations are defined in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; under names beginning with &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Input&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 8-bit A: one of the &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt; configurations in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Values range from &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
After this call, Dynamic Xtreme can only place new poses in the selected regions. Changing the configuration does not remove poses already in VRAM. It is normally set when entering the level, before sprites request their graphics.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicSpaceConfigSP4&amp;lt;/code&amp;gt; is a constant in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; that enables SP4. Other options include &amp;lt;code&amp;gt;!DynamicSpaceConfigSP3&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt;. Choose a region that does not overlap the level&#039;s static graphics.&lt;br /&gt;
&lt;br /&gt;
==== DefineDynamicSpaceConfig ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DefineDynamicSpaceConfig()&amp;lt;/code&amp;gt; specifies which VRAM regions can hold dynamic poses and which are restricted. Use it to create your own configuration instead of selecting a preset with &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%DefineDynamicSpaceConfig(init, end, restricted)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;: ID of the region&#039;s first 16×16 block.&lt;br /&gt;
* &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;: ID of the region&#039;s last 16×16 block. Both endpoints are included.&lt;br /&gt;
* &amp;lt;code&amp;gt;restricted&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; allows dynamic poses in this region; &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; restricts it, preventing the system from placing poses there.&lt;br /&gt;
&lt;br /&gt;
All three parameters are assembly-time constants and are written without &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;. The first block must be less than or equal to the last, and both must be between &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt;. For example, &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt; covers 32 blocks.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Block numbering&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For this configuration, sprite graphics memory is treated as a &#039;&#039;&#039;128×256-pixel&#039;&#039;&#039; grid. The upper 128×128 half corresponds to SP1 and SP2; the lower 128×128 half corresponds to SP3 and SP4.&lt;br /&gt;
&lt;br /&gt;
The grid is divided into 16×16 blocks: &#039;&#039;&#039;8 blocks per row and 16 rows&#039;&#039;&#039;, for a total of 128 blocks. IDs run from left to right, continuing on the next row from top to bottom:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Row of 16×16 tiles !! Col. 0 !! Col. 1 !! Col. 2 !! Col. 3 !! Col. 4 !! Col. 5 !! Col. 6 !! Col. 7&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$09&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$11&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$13&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$15&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$17&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
| &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$19&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$21&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$22&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$23&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$24&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$26&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$27&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
| &amp;lt;code&amp;gt;$28&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$29&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
| &amp;lt;code&amp;gt;$30&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$31&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$32&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$33&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$34&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$35&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$36&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$37&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
| &amp;lt;code&amp;gt;$38&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$39&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$41&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$42&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$43&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$44&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$45&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$46&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$47&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
| &amp;lt;code&amp;gt;$48&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$49&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 10&lt;br /&gt;
| &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$51&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$53&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$54&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$55&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$56&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$57&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 11&lt;br /&gt;
| &amp;lt;code&amp;gt;$58&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$59&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 12&lt;br /&gt;
| &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$61&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$62&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$63&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$64&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$65&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$66&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$67&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 13&lt;br /&gt;
| &amp;lt;code&amp;gt;$68&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$69&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 14&lt;br /&gt;
| &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$71&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$72&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$73&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$74&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$75&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$76&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$77&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 15&lt;br /&gt;
| &amp;lt;code&amp;gt;$78&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$79&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each cell represents a 16×16 tile and contains its block ID. Rows are numbered 0–15 and columns 0–7. These IDs are separate from the 8×8 TileCodes used in DrawInfo.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Section !! Blocks !! Position in the grid&lt;br /&gt;
|-&lt;br /&gt;
| SP1 || &amp;lt;code&amp;gt;$00–$1F&amp;lt;/code&amp;gt; || First four rows.&lt;br /&gt;
|-&lt;br /&gt;
| SP2 || &amp;lt;code&amp;gt;$20–$3F&amp;lt;/code&amp;gt; || Next four rows.&lt;br /&gt;
|-&lt;br /&gt;
| SP3 || &amp;lt;code&amp;gt;$40–$5F&amp;lt;/code&amp;gt; || Next four rows.&lt;br /&gt;
|-&lt;br /&gt;
| SP4 || &amp;lt;code&amp;gt;$60–$7F&amp;lt;/code&amp;gt; || Last four rows.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples from the patch&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These configurations use the same ranges as the patch&#039;s presets. Place them in UberASM&#039;s &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;, before sprites request their poses.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Use SP4 only:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    ; Restrict SP1, SP2, and SP3.&lt;br /&gt;
    %DefineDynamicSpaceConfig($00, $5F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; Make SP4 available for dynamic poses.&lt;br /&gt;
    %DefineDynamicSpaceConfig($60, $7F, $00)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Use SP3 only:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    ; Restrict SP1 and SP2.&lt;br /&gt;
    %DefineDynamicSpaceConfig($00, $3F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; Make SP3 available for dynamic poses.&lt;br /&gt;
    %DefineDynamicSpaceConfig($40, $5F, $00)&lt;br /&gt;
&lt;br /&gt;
    ; Restrict SP4.&lt;br /&gt;
    %DefineDynamicSpaceConfig($60, $7F, $80)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Use SP3 and SP4:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    ; Restrict SP1 and SP2.&lt;br /&gt;
    %DefineDynamicSpaceConfig($00, $3F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; Make SP3 and SP4 available as a single region.&lt;br /&gt;
    %DefineDynamicSpaceConfig($40, $7F, $00)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each example is an alternative configuration. Use one complete configuration covering blocks &amp;lt;code&amp;gt;$00–$7F&amp;lt;/code&amp;gt; with consecutive, non-overlapping regions. Restrict any blocks used by the player, static sprites, or other resources whose graphics must stay in place. The macro does not detect those uses for you.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A must be in 8-bit mode. The macro modifies A and the N/Z flags; it preserves X, Y, carry, DBR, and D, and does not change register sizes.&lt;br /&gt;
* Writes the configuration to &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; at both ends of the specified region. Uses no scratch memory.&lt;br /&gt;
* Does not upload graphics or move poses already in VRAM. Use it to configure the available space when entering the level.&lt;br /&gt;
* Does not report success or failure in carry, and includes neither &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;: execution continues after each call. The &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; in the examples ends UberASM&#039;s &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TakeDynamicRequest ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; enter with 8-bit A and 16-bit X/Y. A, X, and Y return in 8-bit mode; their values may change. X is a valid cache entry index only when carry is set; it does not preserve the sprite index. May overwrite &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$47-$51&amp;lt;/code&amp;gt; when preparing a new upload. Preserves DBR and D on both success and failure. Called with &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;; returns with &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !TakeDynamicRequest&amp;lt;/code&amp;gt; takes a pose ID and looks for its graphics in VRAM. If they are already loaded, it marks them as in use to protect them from replacement. Otherwise, it finds space and schedules an upload for the next NMI, when the game updates graphics between frames.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Input&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 16-bit Y: exact dynamic pose ID.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry set: the graphics are already in VRAM or their upload has been scheduled for the next NMI. X contains the cache entry index that records their location.&lt;br /&gt;
* Carry clear: there is not enough VRAM space, or uploading the pose would exceed the frame&#039;s transfer limit.&lt;br /&gt;
* A, X, and Y return in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RequestPose:&lt;br /&gt;
    REP #$10&lt;br /&gt;
    LDY #!DynamicPoseIDMySprite000&lt;br /&gt;
    JSL !TakeDynamicRequest&lt;br /&gt;
    BCC .Unavailable&lt;br /&gt;
&lt;br /&gt;
    ; X contains the requested pose&#039;s hash table index.&lt;br /&gt;
    ; Your code can save this index to draw the pose.&lt;br /&gt;
RTS&lt;br /&gt;
.Unavailable&lt;br /&gt;
    ; Handle unavailable resources here.&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; is generated from the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized to PascalCase by removing separators and capitalizing each word: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This call returns the cache entry that records the graphics location, but does not store it in the sprite&#039;s variables or fall back to the previous pose if the request fails. Use &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; for that complete behavior.&lt;br /&gt;
&lt;br /&gt;
==== DynamicRoutine ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; sets A, X, and Y to 16-bit mode for its calculations and leaves them in 8-bit mode on return. All three values may change. May overwrite &amp;lt;code&amp;gt;$00-$0B&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$47-$51&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt; occupies &amp;lt;code&amp;gt;$02-$03&amp;lt;/code&amp;gt; in direct page. Preserves D and does not change DBR: set the tables&#039; data bank before calling it. Called with &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;; returns with &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !DynamicRoutine&amp;lt;/code&amp;gt; queues an upload of a pose&#039;s graphics to a specific VRAM location. The transfer takes place during NMI.&lt;br /&gt;
&lt;br /&gt;
The routine needs to know which pose to copy and where to place it. It receives the destination in A, but reads the pose ID from an internal variable called &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; prepares these values before calling it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Required inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Low 8 bits of A: starting block in the dynamic system&#039;s VRAM map. The routine converts this value into a VRAM address.&lt;br /&gt;
* &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt;: internal 16-bit variable containing the ID of the pose to copy.&lt;br /&gt;
* DBR (Data Bank Register): must select the bank containing the pose address and size tables.&lt;br /&gt;
&lt;br /&gt;
Before calling this routine, your code must have allocated enough VRAM space and checked that the upload fits within the frame&#039;s byte limit. &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; handles both tasks.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Reads the address and amount of graphics data for the pose, calculates how to place it at the destination, and adds the required transfers to the VRAM queue. A, X, and Y return in 8-bit mode. Carry does not report success or failure.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;How it works&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When a sprite requests a pose that is not yet in VRAM, &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; finds a place for it. It then stores the ID in &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt; and calls &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; with the selected position in A. &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; prepares the graphics transfer; NMI performs it.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; to load a pose from sprite code. Use &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; to request one directly by ID. Calling &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; also requires you to prepare the internal pose ID, data bank, and destination space described above.&lt;br /&gt;
&lt;br /&gt;
==== GeneralUpload ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; enter with 16-bit A and 8-bit X/Y. A, X, and Y return in 8-bit mode. A and Y may change; with &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;, X is restored from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; with &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, X is not preserved. May overwrite &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$47-$51&amp;lt;/code&amp;gt;, including temporary values used for a new request. Preserves DBR and D. Includes &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;: use &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt; to call the routine containing the macro.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; handles pose uploads like the sprite routines, but lets you choose the variables used to store the pose index, flip settings, and graphics location. This is useful for an entity with several independent poses, or for code that uses its own tables.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%GeneralUpload(Pose16, checkLast, sprite, flip, safeCheck, withoutOffset,&lt;br /&gt;
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,&lt;br /&gt;
    globalFlip, localFlip, lastFlip)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The signature above shows the parameter order; write the actual call on one line.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Pose16&amp;lt;/code&amp;gt;: 0 uses 8-bit pose indices; 1 uses 16-bit indices.&lt;br /&gt;
* &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt;: 1 keeps the previous pose available if the new one cannot be obtained; 0 disables this fallback.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 0 uses your own variables without restoring the sprite index; 1 uses sprite tables and restores X from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 2 works like 1, but requests the pose without comparing or updating &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;flip&amp;lt;/code&amp;gt;: 1 combines &amp;lt;code&amp;gt;globalFlip&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;localFlip&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;; 0 skips this update.&lt;br /&gt;
* &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt;: 1 uses &amp;lt;code&amp;gt;safeLow&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;safeHigh&amp;lt;/code&amp;gt; to prevent duplicate requests in the same frame; 0 skips this check.&lt;br /&gt;
* &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;: 0 adds &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt; to the base ID; 1 uses the supplied ID directly.&lt;br /&gt;
* &amp;lt;code&amp;gt;safeLow&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;safeHigh&amp;lt;/code&amp;gt;: variables holding the low and high bytes of the request&#039;s frame number. They are written even when &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; is 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt;: variable holding the desired pose index.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;: variable holding the last available pose index.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;: variable identifying the entry where Dynamic Xtreme records the graphics location in VRAM. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; means no graphics are available yet.&lt;br /&gt;
* &amp;lt;code&amp;gt;globalFlip&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;localFlip&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: global, local, and combined flip variables.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Additional input&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 16-bit A: base or exact dynamic pose ID, depending on &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
* With &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; must contain the sprite index.&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt;, the macro requests the pose even when &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt; equals &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;, and leaves &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; unchanged. If it obtains the graphics, it stores their location in &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;. If the request fails and &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; is 1, the previous graphics can still be used. &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; still controls whether another request is allowed in the same frame.&lt;br /&gt;
&lt;br /&gt;
The value 2 does not change the index size. Select &amp;lt;code&amp;gt;Pose16 = 1&amp;lt;/code&amp;gt; to use 16-bit index variables. The dynamic pose ID supplied in A is always 16-bit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt; is commonly used for dynamic sprites with several parts, such as a head and body whose graphics must change together. By leaving &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; unchanged, it lets the sprite code coordinate all parts before updating the pose index. The macro does not synchronize the parts itself; the calling code handles that.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Returns carry set when a pose is available for drawing: either the requested pose or the previous one if &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; allows it. Returns carry clear if neither is available. Stores the pose&#039;s state in the supplied variables and marks its graphics as in use to protect them from replacement. The macro ends with &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;; place it at the end of a routine called with &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %GeneralUpload(0, 1, 1, 1, 1, 0, &amp;quot;!NormalSafeFrameLowByte,x&amp;quot;, &amp;quot;!NormalSafeFrameHighByte,x&amp;quot;, &amp;quot;!NormalPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalGlobalFlip,x&amp;quot;, &amp;quot;!NormalLocalFlip,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The example uses normal sprite tables and an 8-bit pose index. &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; is generated from the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; names are normalized to PascalCase by removing separators, as in &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Upload (general macro) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; follows the same requirements as [[#GeneralUpload|GeneralUpload]], with &amp;lt;code&amp;gt;Pose16 = 0&amp;lt;/code&amp;gt;. Enter with 16-bit A and 8-bit X/Y; all three return in 8-bit mode. The &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt; parameter determines whether X is reloaded from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. The macro includes &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%Upload()&amp;lt;/code&amp;gt; is the 8-bit pose index variant of &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt;. It is separate from the sprite alias &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Upload(sprite, checkLast, flip, safeCheck, withoutOffset,&lt;br /&gt;
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,&lt;br /&gt;
    globalFlip, localFlip, lastFlip)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Takes the same inputs as &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt;, but indices stored in variables are always 8-bit. The macro includes the &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; that ends the routine.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt; parameter also accepts 2: this skips the comparison with &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; and leaves that variable unchanged, but still updates &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt; when the pose is obtained. It does not enable 16-bit indices; use &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;Pose16 = 1&amp;lt;/code&amp;gt; for those.&lt;br /&gt;
&lt;br /&gt;
This mode is commonly used to make several parts of a dynamic sprite change their graphics together. For example, your code can handle head and body uploads separately, then update the pose index when both parts should change. Leaving &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; unchanged lets the sprite code control that change.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %Upload(1, 1, 1, 1, 0, &amp;quot;!NormalSafeFrameLowByte,x&amp;quot;, &amp;quot;!NormalSafeFrameHighByte,x&amp;quot;, &amp;quot;!NormalPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalGlobalFlip,x&amp;quot;, &amp;quot;!NormalLocalFlip,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; is generated from the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names use PascalCase, with separators removed: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpriteUpload ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; follows [[#GeneralUpload|GeneralUpload]] with &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;. Enter with 16-bit A and 8-bit X/Y. On return, X contains &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; A and Y may change, and all three are in 8-bit mode. Uses the same scratch memory and ends with &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpriteUpload(withoutOffset, type)&amp;lt;/code&amp;gt; automatically selects the Dynamic Xtreme tables for a normal, cluster, or extended sprite. PIXI&#039;s upload routines use this macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters and inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;: 0 adds &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; to the base ID; 1 uses the exact ID.&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 16-bit A: dynamic pose ID.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: sprite index.&lt;br /&gt;
* Dynamic Xtreme pose and flip tables for the selected sprite type, initialized as described for &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Selects the variables for the specified sprite type. Keeps the previous pose available if the new one is not ready, updates flip settings, and prevents duplicate requests in the same frame. Carry works as it does for &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. The macro includes the &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; that ends the routine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %StandardSpriteUpload(0, &amp;quot;Normal&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; is generated from the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized to PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;, with separators removed.&lt;br /&gt;
&lt;br /&gt;
=== Pose drawing ===&lt;br /&gt;
&lt;br /&gt;
Macros in this category end the routine containing them with &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;. Call the example routines with &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;. A must hold the 16-bit drawing pose ID; prepare &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;) and &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;) as described for &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Draw ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; enter with 16-bit A and 8-bit X/Y. A and Y may change. With &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, X is restored from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; when preparing a valid pose; with &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, the original X is not preserved. If no valid pose is available, X is unchanged. All three return in 8-bit mode. May overwrite &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$45-$4F&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;; with &amp;lt;code&amp;gt;offset = 1&amp;lt;/code&amp;gt;, also &amp;lt;code&amp;gt;$8B-$8C&amp;lt;/code&amp;gt;. Preserves DBR and D. Includes &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%Draw()&amp;lt;/code&amp;gt; draws a dynamic pose. Its arguments specify the graphics, palette, flip settings, and position to use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Draw(offset, sprite, lastPoseHashIndex, lastFlip, palette, xl, xh, yl, yh)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 uses the supplied coordinates; 1 adds the signed 8-bit offsets &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;) and &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 restores the sprite index in X from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; before reading its palette and position; 0 skips this step.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;: variable identifying the entry where Dynamic Xtreme records the pose&#039;s graphics. If it contains &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, nothing is drawn.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variable or value specifying the flip settings for drawing.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: palette variable or value; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; selects palette 8, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; selects 9, and so on up to &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; for F.&lt;br /&gt;
* &amp;lt;code&amp;gt;xl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xh&amp;lt;/code&amp;gt;: variables or values for the low and high bytes of the X position.&lt;br /&gt;
* &amp;lt;code&amp;gt;yl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;yh&amp;lt;/code&amp;gt;: variables or values for the low and high bytes of the Y position.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Draws the pose using the graphics identified by &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt; at the supplied X and Y position. You can pass a sprite&#039;s position variables or specify another position to draw from UberASM or other code.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMySprite_Frame0&lt;br /&gt;
    %Draw(0, 1, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; is generated from the DrawInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized to PascalCase by removing separators, as in &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. The ID must match the available dynamic graphics.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpriteDraw ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; follows [[#Draw|Draw]] and uses the same scratch memory, with &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;. Enter with 16-bit A and 8-bit X/Y. Set X to the sprite index before calling it, because it reads the hash index before restoring &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. All three return in 8-bit mode. Includes &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpriteDraw(offset, type)&amp;lt;/code&amp;gt; draws a dynamic pose using the Dynamic Xtreme tables for the selected sprite type.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters and inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 adds no offset; 1 uses the offsets in &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 16-bit A: drawing pose ID.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: sprite index.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt;: properties and priority.&lt;br /&gt;
* Dynamic Xtreme palette, last flip, and hash index tables for the selected sprite type.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The same result as &amp;lt;code&amp;gt;%Draw()&amp;lt;/code&amp;gt;, using the standard tables. PIXI&#039;s &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; routines use this macro.&lt;br /&gt;
&lt;br /&gt;
For normal sprites, the PIXI routines prepare the coordinate aliases &amp;lt;code&amp;gt;!NormalXLow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!NormalXHigh&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!NormalYLow&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!NormalYHigh&amp;lt;/code&amp;gt;. If you expand the macro directly, these must also be defined, as in this example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!NormalXLow = !SpriteXLow&lt;br /&gt;
!NormalXHigh = !SpriteXHigh&lt;br /&gt;
!NormalYLow = !SpriteYLow&lt;br /&gt;
!NormalYHigh = !SpriteYHigh&lt;br /&gt;
&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMySprite_Frame0&lt;br /&gt;
    %StandardSpriteDraw(0, &amp;quot;Normal&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; is generated from the DrawInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name uses PascalCase, with separators removed: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== DrawStatic ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; enter with 16-bit A and 8-bit X/Y. A and Y may change; X is preserved, but all three return in 8-bit mode. May overwrite &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$45-$4F&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;; with &amp;lt;code&amp;gt;offset = 1&amp;lt;/code&amp;gt;, also &amp;lt;code&amp;gt;$8B-$8C&amp;lt;/code&amp;gt;. In this macro, &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt; does not restore X from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. Preserves DBR and D. Includes &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt; draws a static pose declared with &amp;lt;code&amp;gt;.IsStatic&amp;lt;/code&amp;gt; in the DrawInfo. Its graphics must already be loaded at the VRAM locations specified by its tiles.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%DrawStatic(offset, sprite, lastFlip, palette, xl, xh, yl, yh)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 adds no offset; 1 uses the signed offsets &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;) and &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: retained in the signature, but unused by the current implementation.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: flip variable or value; &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; draws without flipping.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: palette variable or value; &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; selects palette 8, &amp;lt;code&amp;gt;#$02&amp;lt;/code&amp;gt; selects 9, and so on up to &amp;lt;code&amp;gt;#$0E&amp;lt;/code&amp;gt; for F.&lt;br /&gt;
* &amp;lt;code&amp;gt;xl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xh&amp;lt;/code&amp;gt;: variables or values for the low and high bytes of the X position.&lt;br /&gt;
* &amp;lt;code&amp;gt;yl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;yh&amp;lt;/code&amp;gt;: variables or values for the low and high bytes of the Y position.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Additional inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 16-bit A: static drawing pose ID.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;) and &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;): properties and priority.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;): tile number, when all tiles in the pose use the default value of 0. If the DrawInfo specifies other values, those tile numbers are used directly.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Draws the pose without looking up the dynamic graphics cache. Requires neither &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; nor a prior call to &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$80&lt;br /&gt;
    STA !Tile&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMyStaticSprite_Frame0&lt;br /&gt;
    %DrawStatic(0, 1, #$00, #$04, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The example uses tile &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; if the pose is configured to read it from &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, with no flipping and palette A. &amp;lt;code&amp;gt;!PoseIDMyStaticSprite_Frame0&amp;lt;/code&amp;gt; is generated from the DrawInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name uses PascalCase: separators are removed and each word starts with a capital letter, so &amp;lt;code&amp;gt;my_static_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyStaticSprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Paletas ===&lt;br /&gt;
&lt;br /&gt;
These macros let you choose a sprite&#039;s palette, upload its colors, and change them during gameplay.&lt;br /&gt;
&lt;br /&gt;
==== LoadPaletteIDAndAddress ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; enter with 8-bit A; the macro sets the register sizes it needs to calculate addresses. Modifies A and X. Y is not used, but switches to 8-bit mode and loses its high byte if it was previously 16-bit. All three return in 8-bit mode. Writes &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; and reads &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt;. Preserves DBR and D; carry does not report success. Execution continues after the macro.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%LoadPaletteIDAndAddress()&amp;lt;/code&amp;gt; retrieves a palette&#039;s ID and the ROM address of its colors. It selects a palette from the DynamicInfo: 0 for the first, 1 for the second, and so on. It does not upload colors; it provides these values for later use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 8-bit A: palette index within the DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt;: store your DynamicInfo&#039;s 16-bit &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; define here, as shown in the example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: palette ID.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: ROM address of its colors in BGR555 format.&lt;br /&gt;
* A, X, and Y return in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    STA $0E&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    LDA #$01            ; Second palette in the DynamicInfo&lt;br /&gt;
    %LoadPaletteIDAndAddress()&lt;br /&gt;
    ; $00-$01 holds its ID; $02-$04 holds its ROM address.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In PIXI, you can also use &amp;lt;code&amp;gt;%DXLoadPaletteIDAndAddress()&amp;lt;/code&amp;gt;, with the same inputs and results. This variant calls a shared routine, then continues with the next instruction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; is generated from the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized by removing spaces, underscores, and hyphens, then capitalizing the first letter of each word: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignment (general macro) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; enter with 8-bit X/Y and, when &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; is enabled, 16-bit A. When it is disabled, enter with 8-bit A; the table offset is not used. A and Y may change; with &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, X is restored from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; when needed internally; with &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, X is not preserved. All three return in 8-bit mode. May overwrite &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$D5&amp;lt;/code&amp;gt;, and effect temporary memory when applicable. Preserves DBR and D. Ends with &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt; assigns and uploads a palette like &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, but lets you specify the variables holding its options and state. Use it for an additional sprite palette or for code with its own variables.&lt;br /&gt;
&lt;br /&gt;
If the palette is already assigned, it keeps its use timer at 2 to protect it from replacement while in use. If option bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; is set, it also applies the appropriate global effect.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteAssignment(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 uses &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; to access sprite tables; 0 lets you use variables independent of the sprite index.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable receiving the assigned palette. Initialize it to &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Values &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, ..., &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; correspond to palettes 8–F.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteAssignment&amp;lt;/code&amp;gt;: variable or value in &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt; format. &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; lets Dynamic Xtreme choose the destination and upload the colors; &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; uploads the colors to your chosen destination; &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; uses that destination with the colors already loaded in the level.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable or value in &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt; format. E = 1 enables the global effect; E = 0 excludes this palette from it. In manual mode, PPP selects palette 8 (&amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt;) through F (&amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt;). In automatic mode, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; allows all palettes, nonzero &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; allows 8–B, and &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; allows C–F. These options do not use the low four bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteVersion&amp;lt;/code&amp;gt;: variable or value selecting a palette from the DynamicInfo list: 0 for the first, 1 for the second, and so on. Sprite routines use &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; for this.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt;: variable holding the last processed version. Initialize it to &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualIDGroup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt;: together, these identify the palette in manual modes. The first selects the group: &amp;lt;code&amp;gt;#$FE&amp;lt;/code&amp;gt; for normal, &amp;lt;code&amp;gt;#$FC&amp;lt;/code&amp;gt; for cluster, and &amp;lt;code&amp;gt;#$FD&amp;lt;/code&amp;gt; for extended sprites. The second identifies the sprite type; normal sprites use &amp;lt;code&amp;gt;!CustomSpriteNumber,x&amp;lt;/code&amp;gt;, as shown in the example.&lt;br /&gt;
&lt;br /&gt;
You can also define your own groups: for example, &amp;lt;code&amp;gt;manualIDGroup = #$FB&amp;lt;/code&amp;gt; for the player and &amp;lt;code&amp;gt;#$FA&amp;lt;/code&amp;gt; for another type of entity. These are examples, not predefined Dynamic Xtreme values. Choose values not already used by another group, and use &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt; to distinguish resources within each group. Groups &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$FD&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;$FC&amp;lt;/code&amp;gt; are already used by the normal, extended, and cluster sprite routines, respectively.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Additional input&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 16-bit A: &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; for the DynamicInfo containing the palettes.&lt;br /&gt;
* With &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; must contain the sprite index.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry set: a palette is available for drawing. Carry clear: none is available yet.&lt;br /&gt;
* Stores the palette number in &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt; and updates &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt; when processing the version.&lt;br /&gt;
* A, X, and Y return in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %PaletteAssignment(1, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!NormalPaletteAssignment,x&amp;quot;, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalVersion,x&amp;quot;, &amp;quot;!NormalLastVersion,x&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The example uses normal sprite variables. &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; is generated from the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized to PascalCase by removing separators: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Call the example routine with &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt;. The macro includes the &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; that ends the routine, so do not place more code after it.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignmentNoUpload (general macro) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; follows [[#PaletteAssignment_(general_macro)|PaletteAssignment (general macro)]]. In addition to carry, returns Y as described below; do not keep another value in Y if you need it afterward. Outputs in &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; are valid only when a palette was read from the DynamicInfo. Ends with &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; selects a palette like &amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt;, but leaves the color upload pending. This lets you apply a local effect and combine it with the global effect afterward.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters and inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteAssignmentNoUpload(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Takes the same parameters as &amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt;. A receives the 16-bit table offset. Initialize &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;paletteVersion&amp;lt;/code&amp;gt; selects colors from the DynamicInfo list: 0 for the first palette, 1 for the second, and so on. &amp;lt;code&amp;gt;paletteAssignment&amp;lt;/code&amp;gt; selects the mode: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; automatic, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; manual, and &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; manual without uploading colors. &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt; uses &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: E enables the global effect, and PPP selects palette 8–F in manual mode. In automatic mode, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; allows all palettes, nonzero &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; allows 8–B, and &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; allows C–F. To apply a local effect to the DynamicInfo colors afterward, use automatic assignment or manual assignment with upload.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry set: a palette is assigned. Carry clear: assignment failed.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: assigned palette number, in steps of two from &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt;: last processed version.&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: ID of the palette selected from the DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: ROM address of its colors.&lt;br /&gt;
* Y = 1 means the palette was just assigned and its effect must be calculated. Y = 0 means a new assignment does not require recalculation.&lt;br /&gt;
* A, X, and Y return in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
Use the values in &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; only when the call read a palette from the DynamicInfo. If you use an existing level palette without uploading it, disable palette changes, or call from a game mode where processing is skipped, these addresses may contain values left by other code.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
AssignPaletteForEffect:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %PaletteAssignmentNoUpload(1, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!NormalPaletteAssignment,x&amp;quot;, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalVersion,x&amp;quot;, &amp;quot;!NormalLastVersion,x&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After calling &amp;lt;code&amp;gt;AssignPaletteForEffect&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;, check carry and apply the effect using the returned values. Keep Y and &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; intact for the concatenation call.&lt;br /&gt;
&lt;br /&gt;
The macro ends its routine with &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Put the effect code after the &amp;lt;code&amp;gt;JSL AssignPaletteForEffect&amp;lt;/code&amp;gt; call, not after the macro inside that routine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; is generated from the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name uses PascalCase, with separators removed: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpritePaletteAssignment ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; follows [[#PaletteAssignment_(general_macro)|PaletteAssignment (general macro)]], with &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;. Enter with X set to read the sprite&#039;s tables and &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; identifying the same sprite. Restores X from that index when needed internally; A and Y may change. Includes &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpritePaletteAssignment()&amp;lt;/code&amp;gt; uses the palette variables for the specified sprite type. PIXI&#039;s palette assignment routines use this macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters and inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%StandardSpritePaletteAssignment(type, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualIDGroup&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;#$FE&amp;lt;/code&amp;gt; for normal, &amp;lt;code&amp;gt;#$FC&amp;lt;/code&amp;gt; for cluster, or &amp;lt;code&amp;gt;#$FD&amp;lt;/code&amp;gt; for extended sprites.&lt;br /&gt;
* You can also choose your own group, such as &amp;lt;code&amp;gt;#$FB&amp;lt;/code&amp;gt; for the player or &amp;lt;code&amp;gt;#$FA&amp;lt;/code&amp;gt; for another type of entity, provided no other group in your project uses those values.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt;: variable or value identifying the sprite type in manual modes.&lt;br /&gt;
* 16-bit A: &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; for the DynamicInfo containing the palettes.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: sprite index.&lt;br /&gt;
* Dynamic Xtreme palette, option, version, and last-version variables for the selected type, prepared as described for &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The same result as &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;: stores the assigned palette in the sprite table and returns carry set when it can be used for drawing.&lt;br /&gt;
&lt;br /&gt;
The macro includes &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Call the example routine with &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt; and do not place more code after the macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %StandardSpritePaletteAssignment(&amp;quot;Normal&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; is generated from the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized to PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt; when separators are removed.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpritePaletteAssignmentNoUpload ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; follows [[#PaletteAssignmentNoUpload_(general_macro)|PaletteAssignmentNoUpload (general macro)]], with &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;. X and &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; must identify the same sprite on entry. Keep the returned Y and &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; intact if you will concatenate an effect. Includes &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpritePaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; uses the selected sprite type&#039;s variables to assign a palette, leaving the color upload pending.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters and inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%StandardSpritePaletteAssignmentNoUpload(type, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Takes the same parameters and inputs as &amp;lt;code&amp;gt;%StandardSpritePaletteAssignment()&amp;lt;/code&amp;gt;. A must hold the 16-bit palette table offset.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The same result as &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;: stores the assigned palette and returns carry, Y, the ID in &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;, and the address in &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;, under the conditions described in that entry.&lt;br /&gt;
&lt;br /&gt;
The macro includes &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Call the example routine with &amp;lt;code&amp;gt;JSL AssignPaletteForEffect&amp;lt;/code&amp;gt;. Put the effect code after that call.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
AssignPaletteForEffect:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %StandardSpritePaletteAssignmentNoUpload(&amp;quot;Normal&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; is generated from the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name is normalized to PascalCase by removing separators: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== ReplacePalette (general macro) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; enter with 8-bit A, X, and Y, and the source pointer in &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;. A and Y may change; with &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, X is restored from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; with &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, X is not preserved. All three return in 8-bit mode. May overwrite &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; and effect temporary memory when applicable. Preserves DBR and D. Ends with &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ReplacePalette()&amp;lt;/code&amp;gt; replaces the colors of a palette already in use. It works like &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, but lets you choose which variables to read. Other sprites or code sharing that palette will also use the new colors.&lt;br /&gt;
&lt;br /&gt;
It is commonly used after assignment without upload, such as &amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;. First obtain the assigned palette, then put the address of the replacement colors in &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters and inputs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%ReplacePalette(sprite, paletteOption, palette)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 retrieves the sprite index from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 0 uses variables independent of that index.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: palette option variable or value. Bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; controls whether the global effect is applied.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: destination palette variable or value, in steps of two from &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: ROM address of the new BGR555 colors.&lt;br /&gt;
* A in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Result&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Changes the colors without changing the assignment ID. Returns carry set when colors are available for drawing, including the previous colors if the change could not be completed yet. Returns carry clear if no result is available.&lt;br /&gt;
&lt;br /&gt;
Call it when the colors need to change. Calling it every frame makes the system prepare the palette and its effects again each time.&lt;br /&gt;
&lt;br /&gt;
Call the example routine with &amp;lt;code&amp;gt;JSL ReplaceSpritePalette&amp;lt;/code&amp;gt;. The macro includes the &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; that ends the routine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
ReplaceSpritePalette:&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;8&lt;br /&gt;
    STA $03&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
    %ReplacePalette(1, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyAlternatePalette&amp;lt;/code&amp;gt; is the address of a palette inserted from the DynamicInfo&#039;s resources and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name is normalized by removing separators and capitalizing each word: &amp;lt;code&amp;gt;my_alternate_palette&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyAlternatePalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Uploading colors with TransferPalette ====&lt;br /&gt;
&lt;br /&gt;
These macros upload colors to a palette you choose, without automatic assignment. Use them to change a background palette, a palette set aside for a sprite, or colors prepared in RAM.&lt;br /&gt;
&lt;br /&gt;
They also update the game&#039;s palette copies and prepare the effect state, unlike the PPU transfer macros. You do not need to copy the buffers or invalidate their effect flags manually.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Common parameters&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;: first color to change, from &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. This is an 8-bit operand: &amp;lt;code&amp;gt;#$91&amp;lt;/code&amp;gt; starts at color 1 of palette 9; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; uses the number stored in that scratch byte.&lt;br /&gt;
* &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt;: number of bytes to copy. This is an assembly-time value, &#039;&#039;&#039;without &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;&#039;&#039;&#039;: &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; copies 15 colors. It must be positive and even, and the upload must not extend beyond the last CGRAM color.&lt;br /&gt;
* &amp;lt;code&amp;gt;GlobalEffect&amp;lt;/code&amp;gt;: use &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to upload without the global effect, or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; to apply the global effect. This is a fixed option in the call, not a RAM variable.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What GlobalEffect does&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Value !! Behavior&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; || Schedules a transfer of the colors without an effect and updates the SMW and Dynamic Xtreme buffers. If effects are enabled, excludes the modified palettes from the global effect.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; || Stores the original colors so the system can apply the global effect before uploading them. Marks the modified palettes to receive the effect and clears their previous effect flags.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;code&amp;gt;GlobalEffect = 1&amp;lt;/code&amp;gt;, no unaffected version is uploaded first: the upload waits for the effect result. This also prepares a palette for global effects when the current global effect ID is still 0. If palette effects are disabled in the installation, the call uses a direct upload.&lt;br /&gt;
&lt;br /&gt;
These options affect every 16-color palette touched by the upload, not just the copied colors. When uploading with the global effect enabled, supply all visible colors of each affected palette: for example, the 15 colors of a sprite palette, starting at color 1. Do not rely on a partial upload to preserve original colors you have not prepared yet.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Common inputs and results&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Enter with 8-bit A, X, and Y. D must be &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; in LoROM or &amp;lt;code&amp;gt;$3000&amp;lt;/code&amp;gt; in the usual SA-1 Pack context. DBR must allow access to SMW&#039;s palette buffer: &amp;lt;code&amp;gt;$0703&amp;lt;/code&amp;gt; in LoROM or its &amp;lt;code&amp;gt;$6703&amp;lt;/code&amp;gt; mirror in SA-1. The usual banks with RAM mirrors, such as &amp;lt;code&amp;gt;$00-$3F&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$80-$BF&amp;lt;/code&amp;gt;, allow these accesses. If you pass tables using 16-bit addresses, DBR must also allow access to them.&lt;br /&gt;
* Carry set: the direct transfer was accepted, or the original colors were prepared for the global effect. In the latter case, this does not mean the result has already been uploaded to CGRAM.&lt;br /&gt;
* Carry clear: the direct transfer was rejected because of the frame&#039;s data limit. You can retry later; the buffers and effect flags for this upload remain unchanged.&lt;br /&gt;
* A and X may change on both success and failure. Y may change when colors are copied; do not use it to preserve another value across calls. All three return in 8-bit mode in either case. DBR and D are preserved.&lt;br /&gt;
* Calls may modify &amp;lt;code&amp;gt;$68-$6D&amp;lt;/code&amp;gt; when effects are enabled. The &amp;lt;code&amp;gt;FromAddress&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FromTable&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; variants, including &amp;lt;code&amp;gt;ResourceWithLength&amp;lt;/code&amp;gt;, also use &amp;lt;code&amp;gt;$65-$67&amp;lt;/code&amp;gt;. Do not store the source pointer or destination color in scratch memory that the call overwrites before it finishes using those values.&lt;br /&gt;
* Includes neither &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;: execution continues after the macro.&lt;br /&gt;
&lt;br /&gt;
If the source is in RAM, you must keep its contents unchanged until the scheduled transfer takes place. The source data must not cross a bank boundary. For &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;, use an immediate value or a variable that remains valid after the macro changes X and Y; avoid operands indexed by those registers.&lt;br /&gt;
&lt;br /&gt;
Call these macros when the colors need to change, rather than every frame while the palette stays the same. If you use a sprite palette at a fixed destination, restrict it so automatic assignment does not use it.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteFromAddress ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteFromAddress()&amp;lt;/code&amp;gt; uploads colors from an address known at assembly time. This can be a label in your code or a define containing the resource&#039;s full address.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteFromAddress(Address, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Address&amp;lt;/code&amp;gt;: full source address, without &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Other parameters and carry work as described in [[#Uploading_colors_with_TransferPalette|Uploading colors with TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Palette 9, colors 1-F, with the global effect.&lt;br /&gt;
    %TransferPaletteFromAddress(!PaletteMyPalette, #$91, $001E, 1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; is generated when installing a palette declared in a DynamicInfo&#039;s &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; section and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names use PascalCase: spaces, underscores, and hyphens are removed, and each word starts with a capital letter. For example, &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteFromPointer ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteFromPointer()&amp;lt;/code&amp;gt; uses a source address already stored in three consecutive scratch bytes. This is useful when your code selects a palette during gameplay.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteFromPointer(Pointer, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Pointer&amp;lt;/code&amp;gt;: address of the first scratch byte, without &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;. The three bytes must hold the source address in low-byte, high-byte, bank order. For example, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; uses &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Other parameters and carry work as described in [[#Uploading_colors_with_TransferPalette|Uploading colors with TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Put the palette address in $02-$04.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!PaletteMyPalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.b #!PaletteMyPalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
&lt;br /&gt;
    ; Palette 9, colors 1-F, without the global effect.&lt;br /&gt;
    %TransferPaletteFromPointer($02, #$91, $001E, 0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; is generated from a DynamicInfo palette and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name is normalized to PascalCase by removing separators: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteFromTable ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteFromTable()&amp;lt;/code&amp;gt; accepts the source&#039;s two address bytes and bank byte separately. These can come from tables, variables, or immediate values. The macro combines them in &amp;lt;code&amp;gt;$65-$67&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteFromTable(TableAddr, TableBNK, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;TableAddr&amp;lt;/code&amp;gt;: operand read with 16-bit A to obtain the two address bytes.&lt;br /&gt;
* &amp;lt;code&amp;gt;TableBNK&amp;lt;/code&amp;gt;: operand read with 8-bit A to obtain the bank.&lt;br /&gt;
* Other parameters and carry work as described in [[#Uploading_colors_with_TransferPalette|Uploading colors with TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; $02-$03 holds the address; $04 holds the bank.&lt;br /&gt;
    %TransferPaletteFromTable(&amp;quot;$02&amp;quot;, &amp;quot;$04&amp;quot;, #$91, $001E, 1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unlike &amp;lt;code&amp;gt;FromPointer&amp;lt;/code&amp;gt;, the address and bank operands do not need to occupy consecutive bytes. If you read them from tables in your code, the data bank must allow access to those tables.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteResource ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteResource()&amp;lt;/code&amp;gt; uploads an entire palette registered in the DynamicInfo. You do not need to specify its address or byte count.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferPaletteResource(Name, CGRAMOffset, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Name&amp;lt;/code&amp;gt;: normalized palette name, without the &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt; prefix or file extension. The macro uses &amp;lt;code&amp;gt;!Palette&amp;amp;lt;Name&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!Palette&amp;amp;lt;Name&amp;amp;gt;Size&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Other parameters and carry work as described in [[#Uploading_colors_with_TransferPalette|Uploading colors with TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; MyPalette contains 15 colors.&lt;br /&gt;
    %TransferPaletteResource(MyPalette, #$91, 1)&lt;br /&gt;
    BCS .Accepted&lt;br /&gt;
    ; Direct upload rejected: retry later.&lt;br /&gt;
    RTL&lt;br /&gt;
.Accepted&lt;br /&gt;
    ; Continue with the rest of the code.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The example continues at &amp;lt;code&amp;gt;.Accepted&amp;lt;/code&amp;gt; if the direct upload was accepted or the colors were prepared for the global effect. The &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; belongs to the example, not the macro.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; corresponds to &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!PaletteMyPaletteSize&amp;lt;/code&amp;gt;, generated in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; from the DynamicInfo&#039;s &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; section. Names use PascalCase, with spaces, underscores, and hyphens removed: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;. This call does not use &amp;lt;code&amp;gt;!Resource...&amp;lt;/code&amp;gt; defines from the &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; section or converted RGB/HSL palettes from a &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteResourceWithLength ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteResourceWithLength()&amp;lt;/code&amp;gt; uses a registered palette&#039;s address, but copies only the number of bytes you specify.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteResourceWithLength(Name, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Name&amp;lt;/code&amp;gt;: normalized palette name, as in &amp;lt;code&amp;gt;%TransferPaletteResource()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt;: number of bytes to copy, without &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;. Must not exceed the resource size.&lt;br /&gt;
* Other parameters and carry work as described in [[#Uploading_colors_with_TransferPalette|Uploading colors with TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Copy 4 colors to the start of palette 9, without the global effect.&lt;br /&gt;
    %TransferPaletteResourceWithLength(MyPalette, #$90, $0008, 0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; uses &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt;, generated from a DynamicInfo palette and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name is normalized to PascalCase by removing separators: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TransferPaletteCommon&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TransferPaletteData&amp;lt;/code&amp;gt; are internal components shared by these calls. To upload palettes from your code, use the variants above, which also prepare the effect state.&lt;br /&gt;
&lt;br /&gt;
=== Palette effects ===&lt;br /&gt;
&lt;br /&gt;
These macros change a palette&#039;s colors: tint it, adjust its brightness, transition between palettes, or apply an effect saved in a &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
For complete examples, see [[Dynamic_Xtreme_UberASM_guide#Applying_a_global_palette_effect|Applying a global palette effect]] in the UberASM guide, which covers a fixed effect, a cycle, and a transition. [[Dynamic_Xtreme_UberASM_guide#Changing_palettes_during_gameplay|Changing palettes during gameplay]] shows how to upload colors with &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; and check whether the call was accepted.&lt;br /&gt;
&lt;br /&gt;
RGB works with red, green, and blue. HSL works with hue, saturation, and lightness. Choose RGB or HSL macros according to the change you want. See [[Dynamic_Xtreme_files_and_formats#Effect_types|Effect types]] for the available effects.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Which call do you need?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! To… !! Use…&lt;br /&gt;
|-&lt;br /&gt;
| Tint a palette or change its hue, saturation, or lightness. || &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MixAndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Transition from one palette to another. || &amp;lt;code&amp;gt;PaletteTransition&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Apply an effect already defined in a &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; file. || &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DoEffectAndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Give a sprite its own effect while keeping the global effect. || &amp;lt;code&amp;gt;ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; or its HSL variant, after assigning the palette without upload.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To calculate an effect directly, first prepare the original colors with &amp;lt;code&amp;gt;SetRGBBase&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SetHSLBase&amp;lt;/code&amp;gt;, then apply the change. The examples use &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; variants, which work with Dynamic Xtreme&#039;s palette copies so you do not need to specify memory addresses.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; variants produce colors in the format the SNES needs to display them. Calculating them does not upload them automatically: palette handling or a CGRAM transfer completes the upload. When used after &amp;lt;code&amp;gt;PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, the concatenation routines handle both color preparation and the upload.&lt;br /&gt;
&lt;br /&gt;
Set A to 8-bit mode before calling the macros in these examples.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Effect registers and temporary memory&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Base preparation, mixing, transition, conversion, and &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; macros take 8-bit A, X, and Y. Their &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; variants follow the same requirements. Concatenation macros take different inputs, described in their section.&lt;br /&gt;
* These macros prepare their arguments and call the patch routine internally. Execution then continues at the next instruction; they do not include a return that ends your routine.&lt;br /&gt;
* Treat A, X, and Y as temporary; they return in 8-bit mode. Carry does not report success or failure: the result is the colors written to the destination buffer. DBR and D are preserved under the [[#CPU_state_and_temporary_memory|CPU state]] rules.&lt;br /&gt;
* Depending on the operation, they may overwrite &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$45-$54&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8A-$8F&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;$D5-$D7&amp;lt;/code&amp;gt;. These locations hold pointers, lengths, channels, and ratios; do not store values there that must survive the call.&lt;br /&gt;
* Source and destination banks are read with 8-bit A; addresses, offsets, and color counts are read with 16-bit A during preparation. Channels and ratios are read with 8-bit A. The &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; ID is read with 16-bit A. Prepare memory operands at the corresponding size.&lt;br /&gt;
* If your operands are indexed, X and Y must identify their data on entry. Their values may change during the call. In the full variants, arguments must also avoid overlapping temporary values prepared before those arguments are read.&lt;br /&gt;
&lt;br /&gt;
==== Preparing colors: SetRGBBase and SetHSLBase ====&lt;br /&gt;
&lt;br /&gt;
Before changing colors, you need a working copy for the effect calculations. &amp;lt;code&amp;gt;%SetRGBBase()&amp;lt;/code&amp;gt; prepares it for RGB effects; &amp;lt;code&amp;gt;%SetHSLBase()&amp;lt;/code&amp;gt; prepares it for HSL. If the original colors have not changed, you can reuse this copy in later frames.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; variants only require the first color and the number of colors to prepare:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%SetRGBBaseDefault(offset, length)&lt;br /&gt;
%SetHSLBaseDefault(offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; is the first color number, and &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; is the color count. For example, &amp;lt;code&amp;gt;#$0081&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;#$000F&amp;lt;/code&amp;gt; select palette 8&#039;s 15 visible colors.&lt;br /&gt;
&lt;br /&gt;
Use the full versions if you need to choose the addresses to read from and write to:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%SetRGBBase(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%SetHSLBase(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%SetRGBBaseDefault(offset, length)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;%SetHSLBaseDefault(offset, length)&amp;lt;/code&amp;gt; read from &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; and write the result to &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: preparing a sprite palette&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Palette 8, excluding its first, transparent color.&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
    ; Use this variant instead to work in HSL:&lt;br /&gt;
    ; %SetHSLBaseDefault(#$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$81&amp;lt;/code&amp;gt; is palette 8&#039;s second color: the palette starts at color &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;, and the next 15 colors are processed.&lt;br /&gt;
&lt;br /&gt;
==== Mixing colors: Mix and MixAndMerge ====&lt;br /&gt;
&lt;br /&gt;
These macros move the original colors toward values you specify. For example, move red toward 31 and green and blue toward 0 to tint a palette red. Changing the ratios gradually makes the effect fade in.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; parameters specify the target color values, from 0 to 31. The &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; parameters control how far to move toward them: 0 keeps the original, 127 applies the full change, and 64 applies roughly half. The examples write these as &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#$7F&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For RGB, components 1, 2, and 3 are red, green, and blue. For HSL, they are hue, saturation, and lightness.&lt;br /&gt;
&lt;br /&gt;
The end of the name identifies the components to change:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! RGB !! HSL !! Components changed&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;H&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;L&amp;lt;/code&amp;gt; || One.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GB&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SL&amp;lt;/code&amp;gt; || Two.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RGB&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HSL&amp;lt;/code&amp;gt; || All three.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each combination is available as &amp;lt;code&amp;gt;Mix...&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixAndMerge...&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;MixAndMerge...Default&amp;lt;/code&amp;gt;. For example: &amp;lt;code&amp;gt;%MixR()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%MixAndMergeR()&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;%MixAndMergeRDefault()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Supply the selected components&#039; ratios first, then their target values, in the order given by the name. Source and destination addresses, first color, and color count follow. &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; variants omit the addresses.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%MixRGB(r1, r2, r3, v1, v2, v3, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%MixAndMergeRG(r1, r2, v1, v2, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%MixAndMergeLDefault(r3, v3, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RGB example: tinting a palette red&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; Prepare palette 8&#039;s original colors.&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
    ; Move all three components roughly halfway toward pure red.&lt;br /&gt;
    %MixAndMergeRGBDefault(#$40, #$40, #$40, #$1F, #$00, #$00, #$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first three &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt; values set the strength of the change for red, green, and blue. The next three, &amp;lt;code&amp;gt;#$1F, #$00, #$00&amp;lt;/code&amp;gt;, specify pure red as the target. The last two select palette 8&#039;s 15 colors.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HSL example: lightening a palette&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %SetHSLBaseDefault(#$0081, #$000F)&lt;br /&gt;
    %MixAndMergeLDefault(#$40, #$1F, #$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only lightness changes here: &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt; applies roughly half the change, and &amp;lt;code&amp;gt;#$1F&amp;lt;/code&amp;gt; is maximum lightness. This example is independent of the previous one.&lt;br /&gt;
&lt;br /&gt;
==== Transitioning between palettes: PaletteTransition ====&lt;br /&gt;
&lt;br /&gt;
These macros move each original color toward the corresponding color in another palette. Unlike &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt;, each color has its own target. For example, they can transition a sprite from its normal colors to a damage palette.&lt;br /&gt;
&lt;br /&gt;
The variants are &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransitionHSL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransitionRGBAndMerge&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PaletteTransitionHSLAndMerge&amp;lt;/code&amp;gt;. Both &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; variants also have a &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteTransitionRGB(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%PaletteTransitionHSLAndMerge(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%PaletteTransitionRGBAndMergeDefault(r1, r2, r3, targetpal, targetpalbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;targetpal&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;targetpalbnk&amp;lt;/code&amp;gt; specify the target palette&#039;s address and bank. Prepare it with 3 bytes per color, in RGB or HSL according to the macro. The ratios control how far each component moves toward its target.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: calculating an intermediate transition step&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; This example uses the palette copy&#039;s first 15 colors.&lt;br /&gt;
    %SetRGBBaseDefault(#$0000, #$000F)&lt;br /&gt;
    %PaletteTransitionRGBAndMergeDefault(#$40, #$40, #$40, #!PaletteMyTargetRGB, #!PaletteMyTargetRGB&amp;gt;&amp;gt;16, #$0000, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The example assumes &amp;lt;code&amp;gt;!PaletteMyTargetRGB&amp;lt;/code&amp;gt; is an RGB target palette generated when installing a transition &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. Its address is written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized by removing spaces, hyphens, and underscores and capitalizing each word: &amp;lt;code&amp;gt;my_target&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyTarget&amp;lt;/code&amp;gt;. For HSL, use the HSL-converted palette and the corresponding macro.&lt;br /&gt;
&lt;br /&gt;
==== Applying an effect from a file: DoEffect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DoEffect()&amp;lt;/code&amp;gt; applies an effect from a &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; file by ID. The file already defines the effect type, color values, and ratios, so you do not need to supply them individually.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%DoEffect(effect, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%DoEffectAndMerge(effect, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%DoEffectAndMergeDefaultRGB(effect, offset, length)&lt;br /&gt;
%DoEffectAndMergeDefaultHSL(effect, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;effect&amp;lt;/code&amp;gt;: effect ID, such as &amp;lt;code&amp;gt;#!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The source must contain separate RGB or HSL components, depending on the selected effect.&lt;br /&gt;
* &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; writes 3 bytes per color so you can apply further changes.&lt;br /&gt;
* &amp;lt;code&amp;gt;DoEffectAndMerge&amp;lt;/code&amp;gt; writes colors in SNES format. The &amp;lt;code&amp;gt;DefaultRGB&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DefaultHSL&amp;lt;/code&amp;gt; variants select the corresponding base and write to &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: applying an RGB effect to palette 8&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
    %DoEffectAndMergeDefaultRGB(#!PaletteEffectIDMyEffect0, #$81, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; is generated from a &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; file and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name is normalized to PascalCase by removing separators: &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. The final number identifies the effect within the file. For an HSL effect, prepare the HSL base and use &amp;lt;code&amp;gt;%DoEffectAndMergeDefaultHSL()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Converting between RGB and HSL ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%RGBToHSL()&amp;lt;/code&amp;gt; converts RGB colors to HSL; &amp;lt;code&amp;gt;%HSLToRGB()&amp;lt;/code&amp;gt; converts them back. Both read and write 3 bytes per color. Use them when you want to continue modifying a palette with an effect that uses the other color space.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%RGBToHSL(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%HSLToRGB(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: converting the RGB base to HSL&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %RGBToHSL(#DX_PPU_CGRAM_BaseRGBPalette, #DX_PPU_CGRAM_BaseRGBPalette&amp;gt;&amp;gt;16, #DX_PPU_CGRAM_BaseHSLPalette, #DX_PPU_CGRAM_BaseHSLPalette&amp;gt;&amp;gt;16, #$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The example reads palette 8&#039;s 15 colors from the RGB base and writes their equivalents to the HSL base. Prepare the RGB base before calling the conversion.&lt;br /&gt;
&lt;br /&gt;
==== Combining a local effect with the global effect ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; these two macros take 16-bit A, 8-bit X holding the palette value, and 8-bit Y holding the result of assignment without upload. All three return in 8-bit mode. With &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, X is restored from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; with &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, X is not preserved. A and Y may change. Uses effect temporary memory and &amp;lt;code&amp;gt;$F0-$F3&amp;lt;/code&amp;gt;. Preserves DBR and D. Unlike the other effect macros, these include &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; and report availability through carry, including when reusing a previous result.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;%ConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt; apply a local effect to a palette that must also receive the global effect. The sprite calls of the same name use these macros, but the macros let you choose your palette variables.&lt;br /&gt;
&lt;br /&gt;
They are commonly used after &amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; or its sprite variant: assign the palette without uploading colors, then apply the effects. Keep the assignment&#039;s returned values intact for this second call.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%ConcatenateRGBPaletteEffectToGlobal(sprite, paletteOption, palette)&lt;br /&gt;
%ConcatenateHSLPaletteEffectToGlobal(sprite, paletteOption, palette)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 restores the sprite index from &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 0 lets you use your own variables.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: palette option variable or value; set bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; to include the global effect.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable holding the assigned palette, in steps of two from &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 16-bit A: local RGB or HSL effect ID, according to the macro.&lt;br /&gt;
* 8-bit X: copy of the assigned palette value.&lt;br /&gt;
* 8-bit Y: keep the value returned by assignment without upload.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: original color address prepared by that assignment.&lt;br /&gt;
&lt;br /&gt;
Returns carry set if drawing can use the requested effect, or the previous effect while the new one is being prepared. Returns carry clear if no result is available yet. Both macros end the routine with &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: completing assignment without upload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
; Call this routine with JSL after assigning the palette without upload.&lt;br /&gt;
; Keep Y and $02-$04 from that call intact.&lt;br /&gt;
ApplyLocalEffect:&lt;br /&gt;
    LDA !NormalPalette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyEffect0&lt;br /&gt;
    %ConcatenateRGBPaletteEffectToGlobal(1, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; is generated from a &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; file and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name is normalized to PascalCase by removing separators: &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. Use the HSL macro for an HSL effect. If you use Y to read an effect table, save it with &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; and restore it with &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; before concatenating.&lt;br /&gt;
&lt;br /&gt;
==== Choosing addresses and combining several effects ====&lt;br /&gt;
&lt;br /&gt;
The examples&#039; &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; variants choose the addresses for you. Use the full versions to store results elsewhere or apply several effects in sequence. Their address parameters are:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;src&amp;lt;/code&amp;gt;: where to read the original colors; &amp;lt;code&amp;gt;srcbnk&amp;lt;/code&amp;gt;: their bank.&lt;br /&gt;
* &amp;lt;code&amp;gt;dst&amp;lt;/code&amp;gt;: where to write the result; &amp;lt;code&amp;gt;dstbnk&amp;lt;/code&amp;gt;: its bank. The destination must be RAM available to your code.&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: first color to process, counting from 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt;: number of colors to process.&lt;br /&gt;
&lt;br /&gt;
For a fixed address, use &amp;lt;code&amp;gt;#Nombre&amp;lt;/code&amp;gt; for the address and &amp;lt;code&amp;gt;#Nombre&amp;gt;&amp;gt;16&amp;lt;/code&amp;gt; for its bank, as in the RGB-to-HSL example. You can also pass variables containing these values.&lt;br /&gt;
&lt;br /&gt;
The required space depends on the operation:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Operation !! Reads !! Writes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SetRGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SetHSLBase&amp;lt;/code&amp;gt; || Standard palette: 2 bytes per color. || Separate components: 3 bytes per color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransition&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; without &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Separate components: 3 bytes per color. || Separate components: 3 bytes per color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; variants || Separate components: 3 bytes per color. || Standard palette: 2 bytes per color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RGBToHSL&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;HSLToRGB&amp;lt;/code&amp;gt; || Separate components: 3 bytes per color. || Separate components: 3 bytes per color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For example, to apply two effects in sequence, the first must write separate components, without &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt;. The second reads that result and uses &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; to prepare the palette for upload. If one effect uses RGB and the other HSL, convert the colors between steps.&lt;br /&gt;
&lt;br /&gt;
Depending on the operation, the macros use temporary memory including &amp;lt;code&amp;gt;$45-$50&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$51-$53&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8C&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8E&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;$D5-$D7&amp;lt;/code&amp;gt;. Do not store values there that you need to keep after the call.&lt;br /&gt;
&lt;br /&gt;
=== PPU ===&lt;br /&gt;
&lt;br /&gt;
These macros upload graphics to VRAM and colors to CGRAM. The SNES stores graphics in VRAM and their palettes in CGRAM.&lt;br /&gt;
&lt;br /&gt;
A call schedules a transfer for the next NMI, when the game can update those memories. It does not copy the data immediately. The source data must remain available until the transfer takes place.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Which call to use&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! To… !! VRAM !! CGRAM&lt;br /&gt;
|-&lt;br /&gt;
| Supply the source address and bank separately. || &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Supply a full address and let the macro extract the bank. || &amp;lt;code&amp;gt;TransferToVRAMFromAddr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferToCGRAMFromAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Upload an entire resource registered in Dynamic Xtreme. || &amp;lt;code&amp;gt;TransferResourceToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferResourceToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Upload a specified number of bytes from a resource. || &amp;lt;code&amp;gt;TransferResourceToVRAMWithLenght&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferResourceToCGRAMWithLenght&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The normal versions check whether the transfer fits within the frame&#039;s byte limit:&lt;br /&gt;
&lt;br /&gt;
* Carry set: the transfer was scheduled.&lt;br /&gt;
* Carry clear: the transfer was not scheduled because it would exceed the limit. Your code can retry in another frame.&lt;br /&gt;
&lt;br /&gt;
This limit is shared by all Dynamic Xtreme uploads. Several transfers in one frame use the same allowance. These macros modify A and X. If accepted, the transfer leaves A, X, and Y in 8-bit mode; if rejected, A returns in 8-bit mode, but X and Y do not necessarily change size.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Transfer limits and requirements&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Keep these limits in mind before preparing the inputs:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Byte budget and transfer list capacity&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Limit !! What it controls !! Default&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;&lt;br /&gt;
| Total number of bytes that may be requested in one frame. Compared against &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, which counts the bytes requested by all resources.&lt;br /&gt;
| &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt; bytes, shared by Dynamic Xtreme uploads.&lt;br /&gt;
|-&lt;br /&gt;
| VRAM list&lt;br /&gt;
| Number of requests its tables can hold. Each entry uses two bytes per table; &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; allocates the byte count for each table.&lt;br /&gt;
| &amp;lt;code&amp;gt;!VRAMTransferSize = 64&amp;lt;/code&amp;gt;: room for &#039;&#039;&#039;32 requests&#039;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
| CGRAM list&lt;br /&gt;
| Number of requests its tables can hold. &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; sets the number of available entries.&lt;br /&gt;
| &amp;lt;code&amp;gt;!CGRAMTransferSize = 64&amp;lt;/code&amp;gt;: room for &#039;&#039;&#039;64 requests&#039;&#039;&#039;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These are separate limits. For example, 32 VRAM transfers of 2 bytes request only 64 bytes, but fill all 32 entries in the default list. You cannot add another request just because some byte budget remains.&lt;br /&gt;
&lt;br /&gt;
Normal macros check &#039;&#039;&#039;the byte budget&#039;&#039;&#039;, but &#039;&#039;&#039;do not check for a free list entry&#039;&#039;&#039;. If the list is full, your code must postpone the request. Adding it anyway can write beyond the tables and corrupt other variables; there is no separate failure result for a full list. Include requests from other systems in your count: a dynamic pose may require several transfers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; variants skip the byte budget check and add the requested amount to &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;. They do not increase list capacity or the time available for transfers. List counters are 8-bit and the byte counter is 16-bit: do not let them overflow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Transfer requirements&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Value !! Your code&#039;s responsibility&lt;br /&gt;
|-&lt;br /&gt;
| Length&lt;br /&gt;
| Use a &#039;&#039;&#039;positive, even&#039;&#039;&#039; byte count. In DMA, &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; means 65536 bytes, not an empty transfer. PPU macros do not check these conditions.&lt;br /&gt;
|-&lt;br /&gt;
| Source&lt;br /&gt;
| The resource or buffer must contain the requested number of bytes, without crossing a bank boundary. DMA does not continue automatically into the next bank. Split the upload if needed.&lt;br /&gt;
|-&lt;br /&gt;
| RAM source&lt;br /&gt;
| You must keep the buffer unchanged until NMI performs the transfer. The list stores its address, not a copy of its data. In SA-1, use memory that the S-CPU can also read, since it performs the transfer.&lt;br /&gt;
|-&lt;br /&gt;
| VRAM destination&lt;br /&gt;
| The address is measured in 2-byte words. Both the start and end must be within &amp;lt;code&amp;gt;$0000–$7FFF&amp;lt;/code&amp;gt; and within the graphics space available to your resource. For example, &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes starting at &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; occupy words &amp;lt;code&amp;gt;$6000–$60FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| CGRAM destination&lt;br /&gt;
| The destination specifies the first color. Each color occupies 2 bytes; the upload must not extend beyond color &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. For example, 15 colors fit from &amp;lt;code&amp;gt;$F1&amp;lt;/code&amp;gt; onward, or &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Carry set from a normal macro means the request was accepted within the byte budget. It does not confirm that the source, destination, length, or list capacity was validated. These requirements also apply to &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; variants.&lt;br /&gt;
&lt;br /&gt;
Use [[#Uploading_colors_with_TransferPalette|TransferPalette]] to change colors while updating SMW&#039;s palette copies and the effect state. PPU transfers to CGRAM only schedule the copy.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Register state&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Enter with 8-bit A, X, and Y. Normal versions set A to 16-bit mode internally to check the budget, but this entry state also supports &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; variants, especially CGRAM transfers.&lt;br /&gt;
* On acceptance, A and X change and all three registers return in 8-bit mode. Y is not used as a working register, but loses its high byte if you entered with 16-bit indices. On rejection, A changes and returns in 8-bit mode; X and Y retain their original values and sizes.&lt;br /&gt;
* Uses no scratch memory to prepare the request. Writes to the transfer lists and frame byte counter. Preserves DBR and D. DBR must allow access to the counter; some variants may also need that bank to read your memory operands.&lt;br /&gt;
* Source addresses and lengths are read with 16-bit A. The VRAM destination and bank argument are read with 16-bit A; supply the bank as a 16-bit value with a zero high byte. For CGRAM, the source bank and destination color are read with 8-bit A.&lt;br /&gt;
* X changes before several arguments are read. Do not pass X-indexed addresses assuming X will still hold the sprite index. Prefer immediate values or variables independent of X for transfer arguments.&lt;br /&gt;
* Includes neither &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Execution continues after expansion. Check carry from normal variants before another operation changes it. &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; variants do not return a success flag in carry.&lt;br /&gt;
&lt;br /&gt;
These rules also apply to &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;WithLenght&amp;lt;/code&amp;gt; variants: they prepare the arguments and expand the same transfer macro.&lt;br /&gt;
&lt;br /&gt;
==== TransferToVRAM ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; schedules a graphics transfer from ROM or RAM to VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToVRAM(VRAMOffset, ResourceAddr, ResourceBNK, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;VRAMOffset&amp;lt;/code&amp;gt;: VRAM destination address, measured in 2-byte words. For example, copying &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes starting at &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; occupies words &amp;lt;code&amp;gt;$6000-$60FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;ResourceAddr&amp;lt;/code&amp;gt;: source address within its bank.&lt;br /&gt;
* &amp;lt;code&amp;gt;ResourceBNK&amp;lt;/code&amp;gt;: source bank.&lt;br /&gt;
* &amp;lt;code&amp;gt;Lenght&amp;lt;/code&amp;gt;: number of bytes to copy. This spelling is retained because it is the parameter&#039;s actual name.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: scheduling a graphics upload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToVRAM(#$6000, #!ResourceMyGraphics, #!ResourceMyGraphics&amp;gt;&amp;gt;16, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
    ; The transfer will take place during the next NMI.&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; is the address of a resource registered through a DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name is normalized by removing spaces, hyphens, and underscores and capitalizing each word: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;. The resource must contain the requested number of bytes.&lt;br /&gt;
&lt;br /&gt;
==== TransferToVRAMFromAddr ====&lt;br /&gt;
&lt;br /&gt;
Performs the same transfer, but takes the full source address. The macro separates the address and bank for you.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToVRAMFromAddr(VRAMOffset, addr, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Write &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; without &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;; supply the other parameters as in &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferToVRAMFromAddr(#$6000, !ResourceMyGraphics, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; is generated from a DynamicInfo resource and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name is normalized to PascalCase: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferResourceToVRAM and TransferResourceToVRAMWithLenght ====&lt;br /&gt;
&lt;br /&gt;
These variants take the name of a Dynamic Xtreme resource. The first copies the entire resource; the second copies the number of bytes you specify.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferResourceToVRAM(VRAMOffset, ResourceName)&lt;br /&gt;
%TransferResourceToVRAMWithLenght(VRAMOffset, ResourceName, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a resource with defines &amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!ResourceMyGraphicsSize&amp;lt;/code&amp;gt;, use &amp;lt;code&amp;gt;&amp;quot;MyGraphics&amp;quot;&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;ResourceName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: uploading the entire resource&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToVRAM(#$6000, &amp;quot;MyGraphics&amp;quot;)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: uploading only its first $0200 bytes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToVRAMWithLenght(#$6000, &amp;quot;MyGraphics&amp;quot;, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The name and size come from the defines generated in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; when installing DynamicInfo resources. Use the normalized name: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;, with separators removed and each word capitalized.&lt;br /&gt;
&lt;br /&gt;
==== TransferToCGRAM ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt; schedules a color transfer from ROM or RAM to a SNES palette.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToCGRAM(CGRAMOffset, TableAddr, TableBNK, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;: first destination color number, from &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. For example, palette 8 starts at color &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;TableAddr&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TableBNK&amp;lt;/code&amp;gt;: address and bank of the colors to copy.&lt;br /&gt;
* &amp;lt;code&amp;gt;Lenght&amp;lt;/code&amp;gt;: byte count. Each color occupies 2 bytes; 15 colors occupy &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes.&lt;br /&gt;
&lt;br /&gt;
Source colors must use the standard SNES BGR555 format. If you calculated an effect, use its final 2-byte-per-color result, such as the output of an &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; variant.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: copying palette 8&#039;s 15 visible colors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToCGRAM(#$81, #DX_PPU_CGRAM_PaletteWriteMirror+$0102, #DX_PPU_CGRAM_PaletteWriteMirror&amp;gt;&amp;gt;16, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example uses an effect result stored in &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;. Offset &amp;lt;code&amp;gt;$0102&amp;lt;/code&amp;gt; corresponds to color &amp;lt;code&amp;gt;$81&amp;lt;/code&amp;gt;, since each color occupies 2 bytes. It skips the palette&#039;s first color, which is transparent for sprites.&lt;br /&gt;
&lt;br /&gt;
==== TransferToCGRAMFromAddr ====&lt;br /&gt;
&lt;br /&gt;
Performs the same color transfer, but takes the full source address. Write &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; without &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToCGRAMFromAddr(CGRAMOffset, addr, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToCGRAMFromAddr(#$81, DX_PPU_CGRAM_PaletteWriteMirror+$0102, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result is the same as in the previous example: schedules an upload of 15 colors starting at palette 8&#039;s second color.&lt;br /&gt;
&lt;br /&gt;
==== TransferResourceToCGRAM and TransferResourceToCGRAMWithLenght ====&lt;br /&gt;
&lt;br /&gt;
These variants copy colors from a resource registered in Dynamic Xtreme. The first uses the full resource size; the second uses the byte count you specify.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferResourceToCGRAM(CGRAMOffset, ResourceName)&lt;br /&gt;
%TransferResourceToCGRAMWithLenght(CGRAMOffset, ResourceName, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: copying an entire color resource&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToCGRAM(#$80, &amp;quot;MyColors&amp;quot;)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: copying only 15 colors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToCGRAMWithLenght(#$81, &amp;quot;MyColors&amp;quot;, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These examples assume a general color resource with defines &amp;lt;code&amp;gt;!ResourceMyColors&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!ResourceMyColorsSize&amp;lt;/code&amp;gt;, generated in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; from a DynamicInfo. Use the normalized name: &amp;lt;code&amp;gt;my_colors&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MyColors&amp;lt;/code&amp;gt;. In the second example, the resource must begin with the 15 colors to copy, without a transparent color before them.&lt;br /&gt;
&lt;br /&gt;
==== Forced variants ====&lt;br /&gt;
&lt;br /&gt;
All transfers above have a variant whose name begins with &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;. These schedule the transfer even if it exceeds the frame&#039;s byte limit. The byte count is still added to the frame&#039;s total.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! VRAM !! CGRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferToVRAMFromAddr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferToCGRAMFromAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferResourceToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferResourceToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferResourceToVRAMWithLenght&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferResourceToCGRAMWithLenght&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
They take the same parameters as the versions without &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;. Carry does not report whether the transfer was accepted. Set A to 8-bit mode before using them; A, X, and Y return in 8-bit mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %ForcedTransferResourceToVRAM(#$6000, &amp;quot;MyGraphics&amp;quot;)&lt;br /&gt;
    ; Do not check carry for this variant.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt; corresponds to the DynamicInfo resource &amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Use the normalized name, as in &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; for uploads that need priority and whose data size you already control. Forcing too much data can exceed the time available for graphics updates. For other uploads, use the normal variants and check carry.&lt;br /&gt;
&lt;br /&gt;
=== Math ===&lt;br /&gt;
&lt;br /&gt;
These macros multiply and divide using SNES or SA-1 hardware, depending on the ROM. They use unsigned numbers: values represent positive quantities or zero.&lt;br /&gt;
&lt;br /&gt;
Set A to 8-bit mode before calling them. The macros do not change the size of A, X, or Y for you.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registers and temporary memory:&#039;&#039;&#039; all macros in this category, including &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;After...&amp;lt;/code&amp;gt; variants, modify A and N/Z, preserve X, Y, carry, DBR, and D, and use no scratch memory. They retain their entry register sizes; A must be 8-bit for correct hardware writes. DBR must allow access to the SNES or SA-1 arithmetic registers as appropriate. Includes neither &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;; execution continues after the macro. Results are in the hardware registers listed below, not in A. Carry does not report success or arithmetic overflow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Writing the arguments&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Mul&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Div&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MulAfterMul&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;DivAfterDiv&amp;lt;/code&amp;gt; append the argument directly to &amp;lt;code&amp;gt;LDA&amp;lt;/code&amp;gt;. Put the argument in quotation marks with a leading space: &amp;lt;code&amp;gt;&amp;quot; #$05&amp;quot;&amp;lt;/code&amp;gt; produces &amp;lt;code&amp;gt;LDA #$05&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can also start the argument with &amp;lt;code&amp;gt;.b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;.l&amp;lt;/code&amp;gt; to select the memory access encoding. For example, if &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; holds the number to multiply:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot;.b $02&amp;quot;, &amp;quot; #$07&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This generates &amp;lt;code&amp;gt;LDA.b $02&amp;lt;/code&amp;gt; to read the first number and &amp;lt;code&amp;gt;LDA #$07&amp;lt;/code&amp;gt; for the second. These suffixes control address encoding; they do not change A&#039;s size. The multiplication still uses 8-bit numbers.&lt;br /&gt;
&lt;br /&gt;
Variants with &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt;, along with &amp;lt;code&amp;gt;MulAfterDiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DivAfterMul&amp;lt;/code&amp;gt;, already add a space before their arguments. Write their values normally, as in &amp;lt;code&amp;gt;%MulW(#$05, #$07)&amp;lt;/code&amp;gt;. The current implementation does not accept &amp;lt;code&amp;gt;.b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;.l&amp;lt;/code&amp;gt; suffixes in the same way for these variants, because the inserted space would separate &amp;lt;code&amp;gt;LDA&amp;lt;/code&amp;gt; from the suffix.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What does W mean?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The hardware needs a short time to finish the calculation. Macros with &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; include that wait, so you can read the result immediately afterward. Versions without &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; let you run other code while the hardware calculates, but you must allow enough time before reading the result. Use a &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; variant if you need the result in the next instruction.&lt;br /&gt;
&lt;br /&gt;
Read results through these defines:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!MultiplicationResult&amp;lt;/code&amp;gt;: 16-bit multiplication result.&lt;br /&gt;
* &amp;lt;code&amp;gt;!DivisionResult&amp;lt;/code&amp;gt;: 16-bit division quotient.&lt;br /&gt;
* &amp;lt;code&amp;gt;!RemainderResult&amp;lt;/code&amp;gt;: 16-bit division remainder.&lt;br /&gt;
&lt;br /&gt;
These defines select the correct SNES or SA-1 address. The next calculation may overwrite previous results; save them if you need them later.&lt;br /&gt;
&lt;br /&gt;
==== Mul and MulW ====&lt;br /&gt;
&lt;br /&gt;
Multiply two 8-bit values to produce a 16-bit result.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Mul(a, b)&lt;br /&gt;
%MulW(a, b)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; can be immediate values, such as &amp;lt;code&amp;gt;#$06&amp;lt;/code&amp;gt;, or 8-bit variables.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: 6 × 7 = 42&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %MulW(#$06, #$07)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $002A, or 42&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The call without a wait is &amp;lt;code&amp;gt;%Mul(&amp;quot; #$06&amp;quot;, &amp;quot; #$07&amp;quot;)&amp;lt;/code&amp;gt;. Do not read its result immediately: first run other code that does not use the multiplication or division hardware.&lt;br /&gt;
&lt;br /&gt;
==== Div and DivW ====&lt;br /&gt;
&lt;br /&gt;
Divide a 16-bit number by an 8-bit number. Supply the 16-bit number as two bytes: high byte first, then low byte.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Div(ah, al, b)&lt;br /&gt;
%DivW(ah, al, b)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;ah&amp;lt;/code&amp;gt;: high byte of the number to divide.&lt;br /&gt;
* &amp;lt;code&amp;gt;al&amp;lt;/code&amp;gt;: low byte of the same number.&lt;br /&gt;
* &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;: divisor, from 1 to 255.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: 300 ÷ 7 = 42, remainder 6&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; 300 = $012C: high byte $01, low byte $2C.&lt;br /&gt;
    %DivW(#$01, #$2C, #$07)&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $002A, or 42&lt;br /&gt;
    LDA !RemainderResult         ; A = $0006&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also pass a 16-bit variable as two arguments: &amp;lt;code&amp;gt;%DivW(MiNumero+1, MiNumero, #$07)&amp;lt;/code&amp;gt;. Here, &amp;lt;code&amp;gt;MiNumero&amp;lt;/code&amp;gt; represents a variable defined by your code.&lt;br /&gt;
&lt;br /&gt;
==== Continuing from the previous result ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;AfterMul&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AfterDiv&amp;lt;/code&amp;gt; variants use the previous calculation&#039;s result as the first number. You only need to supply the second number.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Macro !! Calculation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MulAfterMul(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MulWAfterMul(b)&amp;lt;/code&amp;gt; || Multiplies the low 8 bits of the previous multiplication result by b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MulAfterDiv(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MulWAfterDiv(b)&amp;lt;/code&amp;gt; || Multiplies the low 8 bits of the previous quotient by b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DivAfterMul(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DivWAfterMul(b)&amp;lt;/code&amp;gt; || Divides the full previous multiplication result by b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DivAfterDiv(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DivWAfterDiv(b)&amp;lt;/code&amp;gt; || Divides the full previous quotient by b.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
W still means the new result can be read immediately afterward. &amp;lt;code&amp;gt;After...&amp;lt;/code&amp;gt; variants already include the wait needed to read the previous calculation&#039;s result.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: two multiplications, (6 × 7) × 2 = 84&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot; #$06&amp;quot;, &amp;quot; #$07&amp;quot;)&lt;br /&gt;
    %MulWAfterMul(#$02)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $0054, or 84&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: division followed by multiplication, (100 ÷ 4) × 3 = 75&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Div(&amp;quot; #$00&amp;quot;, &amp;quot; #$64&amp;quot;, &amp;quot; #$04&amp;quot;)&lt;br /&gt;
    %MulWAfterDiv(#$03)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $004B, or 75&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: multiplication followed by division, (20 × 15) ÷ 4 = 75&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot; #$14&amp;quot;, &amp;quot; #$0F&amp;quot;)&lt;br /&gt;
    %DivWAfterMul(#$04)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $004B, or 75&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example: two divisions, (300 ÷ 3) ÷ 4 = 25&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Div(&amp;quot; #$01&amp;quot;, &amp;quot; #$2C&amp;quot;, &amp;quot; #$03&amp;quot;)&lt;br /&gt;
    %DivWAfterDiv(#$04)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $0019, or 25&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In multiplication, the first number is always limited to 8 bits. If the previous result exceeds 255, &amp;lt;code&amp;gt;MulAfterMul&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;MulAfterDiv&amp;lt;/code&amp;gt; uses only its low byte. The division macros in this table use the full 16-bit previous result.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_UberASM_guide&amp;diff=21396</id>
		<title>Dynamic Xtreme UberASM guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_UberASM_guide&amp;diff=21396"/>
		<updated>2026-10-25T21:57:21Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: Created page with &amp;quot;{{Select Language|Dynamic_Xtreme_UberASM_guide}}  This article explains how to use Dynamic Xtreme from UberASM to configure a level&amp;#039;s resources and change graphics and colors during gameplay. Examples cover restricting palettes, choosing VRAM space for dynamic sprites, creating animations, and changing the player&amp;#039;s graphics.  == Requirements ==  * Have UberASMTool installed and configured to insert code into your ROM. * Have Dynamic Xtreme installed with the features req...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_UberASM_guide}}&lt;br /&gt;
&lt;br /&gt;
This article explains how to use Dynamic Xtreme from UberASM to configure a level&#039;s resources and change graphics and colors during gameplay. Examples cover restricting palettes, choosing VRAM space for dynamic sprites, creating animations, and changing the player&#039;s graphics.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
* Have UberASMTool installed and configured to insert code into your ROM.&lt;br /&gt;
* Have Dynamic Xtreme installed with the features required by your chosen example. See the [[Dynamic_Xtreme_Quick_Start|Quick Start guide]] for installation.&lt;br /&gt;
&lt;br /&gt;
See the [[Dynamic_Xtreme_ASM_API|ASM API reference]] for call parameters and variable usage.&lt;br /&gt;
&lt;br /&gt;
Each example requires the following features:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Example !! Required features&lt;br /&gt;
|-&lt;br /&gt;
| [[#Setting_aside_palettes_for_other_resources|Setting aside palettes for other resources]]&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Choosing_VRAM_space_for_dynamic_sprites|Choosing VRAM space for dynamic sprites]]&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;. Drawing these poses with Dynamic Xtreme also requires &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Setting_the_transfer_limit_per_frame|Setting the transfer limit per frame]]&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; for graphics uploads or &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; for palette uploads; both if you use both types.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Creating_graphics_animations|Creating graphics animations]]&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;, since the example uploads graphics and a palette. Add &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; if you set &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt; to 1 to use the global effect.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Changing_palettes_during_gameplay|Changing palettes during gameplay]]&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; and, with &amp;lt;code&amp;gt;!PaletteGlobalEffect = 1&amp;lt;/code&amp;gt; as in the example, &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;. To upload without the global effect, use &amp;lt;code&amp;gt;!PaletteGlobalEffect = 0&amp;lt;/code&amp;gt;; only &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; is then required.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Changing_the_player&#039;s_graphics|Changing the player&#039;s graphics]]&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; and its dependencies, &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Applying_a_global_palette_effect|Applying a global palette effect]], fixed, cyclic, or transitional&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The graphics animation in this guide copies data to a fixed VRAM destination: it does not require &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;. See the [[Dynamic_Xtreme_ASM_API#Features_required_to_use_the_API|API feature table]] for the routines and macros enabled by each feature.&lt;br /&gt;
&lt;br /&gt;
== Preparing the examples ==&lt;br /&gt;
&lt;br /&gt;
Each example stands on its own. Save the level code in the appropriate UberASMTool folder and add it to the list. If you combine examples in one file, merge their &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; blocks so the labels are not duplicated.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt; prepares data while the level loads.&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; sets options when entering the level. The palette restriction example uses this block.&lt;br /&gt;
* &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; runs during gameplay, once per frame.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme defines and macros must be available in UberASMTool through the integration performed during installation. Declare any additional graphics, palettes, or effects in the ASM using the corresponding includes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MyResources.dynamicinfo&amp;quot;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/MyEffect.paleffect&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Paths are relative to the ASM file. Include only files used by your example. You can also use Dynamic Xtreme&#039;s traditional folders, as explained in [[Dynamic_Xtreme_files_and_formats|Files and formats]].&lt;br /&gt;
&lt;br /&gt;
After adding or modifying these resources, install Dynamic Xtreme first, then UberASMTool. If you only change the ASM logic, rerun UberASMTool.&lt;br /&gt;
&lt;br /&gt;
Names beginning with &amp;lt;code&amp;gt;RAM_LIBRE_...&amp;lt;/code&amp;gt; in these examples are placeholders: replace them with free RAM addresses before inserting the code. They are not Dynamic Xtreme defines. Allocate the specified number of bytes and use separate addresses for variables that must coexist. Check that the game, Dynamic Xtreme, Lunar Magic, and other resources do not use them; an address free in the original SMW may already be in use in your ROM. You can look for addresses in the [https://www.smwcentral.net/?p=memorymap&amp;amp;game=smw&amp;amp;u=0&amp;amp;address=&amp;amp;sizeOperation=%3D&amp;amp;sizeValue=&amp;amp;region%5B%5D=ram&amp;amp;type=Empty&amp;amp;description= SMW Central RAM map filtered to empty space].&lt;br /&gt;
&lt;br /&gt;
If you use a short SMW RAM address outside &#039;&#039;&#039;direct page&#039;&#039;&#039;, add &amp;lt;code&amp;gt;|!addr&amp;lt;/code&amp;gt; for the appropriate LoROM or SA-1 remapping. For example, when choosing the timer address:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!AnimationTimer = RAM_LIBRE_ANIM_TIMER|!addr&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Replace &amp;lt;code&amp;gt;RAM_LIBRE_ANIM_TIMER&amp;lt;/code&amp;gt; with your chosen address and keep &amp;lt;code&amp;gt;|!addr&amp;lt;/code&amp;gt;. Direct page addresses use the execution context&#039;s D base and do not use this remapping. If you choose a full 24-bit address, check its bank and whether the example&#039;s instructions can access it; &amp;lt;code&amp;gt;|!addr&amp;lt;/code&amp;gt; is intended here for short addresses outside direct page.&lt;br /&gt;
&lt;br /&gt;
== Setting aside palettes for other resources ==&lt;br /&gt;
&lt;br /&gt;
If an animation, HUD, or other resource needs a fixed palette, set it aside so Dynamic Xtreme does not choose it when assigning palettes to dynamic sprites.&lt;br /&gt;
&lt;br /&gt;
Write &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; to its &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; entry. Each entry occupies 2 bytes. For example, palette 9 uses offset &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;: 9 × 2.&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme_ASM_API#Palettes_and_the_global_effect|Palettes and the global effect in the API]] for an explanation of this table.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$FFFE&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_ID+$12    ; Set aside palette 9&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To set aside several palettes, write the same value to each entry:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Palette !! Offset&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| A || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| B || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| C || &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| D || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| E || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| F || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This prevents automatic assignment from claiming the palette; it does not upload colors. A resource configured to use it manually can still change its colors, so do not also assign it to another resource that needs a different palette.&lt;br /&gt;
&lt;br /&gt;
== Choosing VRAM space for dynamic sprites ==&lt;br /&gt;
&lt;br /&gt;
Dynamic sprites need VRAM space for their poses. Choose a region not used by the level&#039;s static graphics.&lt;br /&gt;
&lt;br /&gt;
The [[SMW_VRAM_Map#Levels|SMW VRAM map on SNESLab]] shows the regions corresponding to SP1, SP2, SP3, and SP4.&lt;br /&gt;
&lt;br /&gt;
For example, to allow SP4:&lt;br /&gt;
&lt;br /&gt;
[[Dynamic_Xtreme_ASM_API#DynamicPoseSpaceConfig|DynamicPoseSpaceConfig]] takes one of the predefined configurations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need more space and the level allows it, choose &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; for SP3 and SP4, or &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt; for SP2, SP3, and SP4. Other options include half pages and configurations that share space with the player or DSX.&lt;br /&gt;
&lt;br /&gt;
The available defines are listed in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; and the [[Dynamic_Xtreme_ASM_API#Space_configurations_for_dynamic_poses|API configuration table]]. Set the configuration before the level starts loading poses; changing it does not automatically remove poses already in VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Creating a custom configuration ===&lt;br /&gt;
&lt;br /&gt;
Use [[Dynamic_Xtreme_ASM_API#DefineDynamicSpaceConfig|DefineDynamicSpaceConfig]] to combine regions differently. This example makes the first half of SP3 and all of SP4 available, restricting everything else:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    ; Restrict SP1 and SP2.&lt;br /&gt;
    %DefineDynamicSpaceConfig($00, $3F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; Make the first half of SP3 available.&lt;br /&gt;
    %DefineDynamicSpaceConfig($40, $4F, $00)&lt;br /&gt;
&lt;br /&gt;
    ; Restrict the second half of SP3.&lt;br /&gt;
    %DefineDynamicSpaceConfig($50, $5F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; Make SP4 available.&lt;br /&gt;
    %DefineDynamicSpaceConfig($60, $7F, $00)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first two parameters are the first and last 16×16 blocks, both inclusive. The third is &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; to allow dynamic poses or &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; to restrict the region. IDs run left to right and top to bottom, with 8 blocks per row. The [[Dynamic_Xtreme_ASM_API#DefineDynamicSpaceConfig|macro documentation]] includes the full numbering table.&lt;br /&gt;
&lt;br /&gt;
This replaces the preset configuration call; do not run both configurations in sequence. Adjust the ranges to cover blocks &amp;lt;code&amp;gt;$00–$7F&amp;lt;/code&amp;gt; without overlaps, and restrict regions needed by other level graphics. Like the previous example, this requires &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Setting the transfer limit per frame ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; sets how many bytes normal Dynamic Xtreme uploads may schedule in a frame. Dynamic poses, animations, and other transfers using its macros share this limit.&lt;br /&gt;
&lt;br /&gt;
See these variables in [[Dynamic_Xtreme_ASM_API#Counters_and_data_per_frame|Counters and data per frame in the API]].&lt;br /&gt;
&lt;br /&gt;
The default is &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, or 2048 bytes. This example increases it to &amp;lt;code&amp;gt;$0A00&amp;lt;/code&amp;gt;, or 2560 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0A00&lt;br /&gt;
    STA.l DX_Dynamic_MaxDataPerFrame&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Increasing it allows more uploads to be requested in one frame, but does not give the SNES more time to perform them. Too much data can cause visual problems. Adjust the value for your level and test with its sprites and animations running together.&lt;br /&gt;
&lt;br /&gt;
Normal macros return carry clear if an upload does not fit within the limit. Keep the current graphics or colors and retry later. &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; variants skip the check and still add their bytes to the total.&lt;br /&gt;
&lt;br /&gt;
== Creating graphics animations ==&lt;br /&gt;
&lt;br /&gt;
This example creates a graphics animation: a table gives each image&#039;s starting address, a timer controls when to change images, and the previous image stays in place if the transfer is rejected.&lt;br /&gt;
&lt;br /&gt;
It uses [[Dynamic_Xtreme_ASM_API#TransferToVRAM|TransferToVRAM]] for graphics changes, its [[Dynamic_Xtreme_ASM_API#Forced_variants|Forced variant]] for the initial upload, and [[Dynamic_Xtreme_ASM_API#TransferPaletteResource|TransferPaletteResource]] for colors. Follow those links for parameters, registers, and results.&lt;br /&gt;
&lt;br /&gt;
Declare the example&#039;s files in &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Choose free RAM here: one separate byte per variable.&lt;br /&gt;
!CurrentPoseIndex = RAM_LIBRE_ANIM_POSE&lt;br /&gt;
!AnimationTimer = RAM_LIBRE_ANIM_TIMER&lt;br /&gt;
!PaletteLoaded = RAM_LIBRE_ANIM_PALETA&lt;br /&gt;
&lt;br /&gt;
; Frames to wait before attempting the next change.&lt;br /&gt;
!TimePerPose = $03&lt;br /&gt;
&lt;br /&gt;
; Bytes per image: one 8x8 4bpp tile occupies $0020.&lt;br /&gt;
!DataSend = $0200&lt;br /&gt;
&lt;br /&gt;
; Number of images used.&lt;br /&gt;
!NumberOfPoses = $05&lt;br /&gt;
&lt;br /&gt;
; Source: installed resource. You can also use !AN2Buffer2.&lt;br /&gt;
!Source = !ResourceSMMArrow&lt;br /&gt;
&lt;br /&gt;
; VRAM destination address.&lt;br /&gt;
!Destination = !BG2Line0&lt;br /&gt;
&lt;br /&gt;
; Installed palette and first destination color.&lt;br /&gt;
!Palette = &amp;quot;SMMArrowPal&amp;quot;&lt;br /&gt;
!PaletteDestination = $71&lt;br /&gt;
&lt;br /&gt;
; 0 = no global effect; 1 = apply the global effect.&lt;br /&gt;
!PaletteGlobalEffect = 0&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    STZ !CurrentPoseIndex&lt;br /&gt;
    LDA #!TimePerPose&lt;br /&gt;
    STA !AnimationTimer&lt;br /&gt;
    STZ !PaletteLoaded&lt;br /&gt;
&lt;br /&gt;
    %ForcedTransferToVRAM(#!Destination, #!Source, #((!Source&amp;gt;&amp;gt;16)&amp;amp;$FF), #!DataSend)&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteLoaded&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; Retry the palette if init&#039;s upload was rejected.&lt;br /&gt;
    LDA !PaletteLoaded&lt;br /&gt;
    BNE .Animate&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCS .PaletteReady&lt;br /&gt;
    RTL&lt;br /&gt;
.PaletteReady&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteLoaded&lt;br /&gt;
&lt;br /&gt;
.Animate&lt;br /&gt;
    LDA !AnimationTimer&lt;br /&gt;
    BEQ .NextPose&lt;br /&gt;
    DEC !AnimationTimer&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
.NextPose&lt;br /&gt;
    LDA !CurrentPoseIndex&lt;br /&gt;
    INC A&lt;br /&gt;
    CMP #!NumberOfPoses&lt;br /&gt;
    BCC .SelectPose&lt;br /&gt;
    LDA #$00&lt;br /&gt;
.SelectPose&lt;br /&gt;
    STA $05&lt;br /&gt;
    ASL&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l PosesTable,x&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC.w #!Source&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    %TransferToVRAM(#!Destination, $00, #((!Source&amp;gt;&amp;gt;16)&amp;amp;$FF), #!DataSend)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA $05&lt;br /&gt;
    STA !CurrentPoseIndex&lt;br /&gt;
    LDA #!TimePerPose&lt;br /&gt;
    STA !AnimationTimer&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
PosesTable:&lt;br /&gt;
    dw $0000&lt;br /&gt;
    dw !DataSend*$01&lt;br /&gt;
    dw !DataSend*$02&lt;br /&gt;
    dw !DataSend*$03&lt;br /&gt;
    dw !DataSend*$04&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What you can customize&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!TimePerPose&amp;lt;/code&amp;gt;: wait time. With &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;, a change is attempted every four frames: three to count down the timer and one to make the change.&lt;br /&gt;
* &amp;lt;code&amp;gt;!DataSend&amp;lt;/code&amp;gt;: bytes per image. &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; is 16 8×8 tiles in 4bpp.&lt;br /&gt;
* &amp;lt;code&amp;gt;!NumberOfPoses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PosesTable&amp;lt;/code&amp;gt;: image count and offsets within the source. The example uses the first five images in &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;. Extend the table if you add more.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Source&amp;lt;/code&amp;gt;: graphics address. The example reads &amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt; directly; use &amp;lt;code&amp;gt;!AN2Buffer2&amp;lt;/code&amp;gt; to animate graphics already prepared by Lunar Magic.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Destination&amp;lt;/code&amp;gt;: VRAM region to update. Place tiles in the level that use this region, and check that another resource does not overwrite it.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteDestination&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt;: palette resource, first destination color, and participation in the global effect.&lt;br /&gt;
&lt;br /&gt;
Replace the three RAM placeholders at the start with addresses available throughout the level: each variable needs its own byte. These are not temporary scratch bytes. &amp;lt;code&amp;gt;!PaletteLoaded&amp;lt;/code&amp;gt; lets the code retry a rejected palette upload without repeating it once accepted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt; are generated when installing the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Their names are normalized to PascalCase by removing separators; here, the capitalization in &amp;lt;code&amp;gt;SMMArrow&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; is preserved.&lt;br /&gt;
&lt;br /&gt;
All images used must be in the same source bank. The initial graphics upload uses &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;; later changes respect the frame&#039;s data limit. If an upload is rejected, the code keeps the previous image and retries next frame without advancing the index or resetting the timer.&lt;br /&gt;
&lt;br /&gt;
The timer advances each time &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; runs. To stop the animation while paused or while the action is frozen, check &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; before counting it down.&lt;br /&gt;
&lt;br /&gt;
== Changing palettes during gameplay ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; macros upload colors while keeping SMW&#039;s and Dynamic Xtreme&#039;s palette copies up to date. They also prepare palette effects, so you do not need to copy buffers or clear flags manually.&lt;br /&gt;
&lt;br /&gt;
This example uses [[Dynamic_Xtreme_ASM_API#TransferPaletteResource|TransferPaletteResource]]; see its API entry for the parameters and carry results.&lt;br /&gt;
&lt;br /&gt;
The example uses &amp;lt;code&amp;gt;SMMArrowPal.bin&amp;lt;/code&amp;gt;, a 15-color file (&amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes), and changes colors 1–F of palette 7. Color 0 is left unchanged.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;, declare the graphics as a general resource and the palette under &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the level ASM:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Choose one byte of free RAM here.&lt;br /&gt;
!PaletteChangePending = RAM_LIBRE_CAMBIO_PALETA&lt;br /&gt;
&lt;br /&gt;
!Palette = &amp;quot;SMMArrowPal&amp;quot;&lt;br /&gt;
!PaletteDestination = $71&lt;br /&gt;
!PaletteGlobalEffect = 1&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteChangePending&lt;br /&gt;
    ; Continue to the first upload attempt.&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA !PaletteChangePending&lt;br /&gt;
    BNE .TryTransfer&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.TryTransfer&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    ; Confirm the change only if the call was accepted.&lt;br /&gt;
    STZ !PaletteChangePending&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Replace &amp;lt;code&amp;gt;RAM_LIBRE_CAMBIO_PALETA&amp;lt;/code&amp;gt; with one byte of free RAM available throughout the level. &amp;lt;code&amp;gt;!PaletteChangePending&amp;lt;/code&amp;gt; is set to 1 when a change is requested and returns to 0 only when the macro returns carry set. If the call fails, the change remains pending and is retried next frame. Once accepted, the upload is not repeated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt; selects the resource, and &amp;lt;code&amp;gt;!PaletteDestination&amp;lt;/code&amp;gt; selects the first destination color. &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt;, the macro&#039;s last parameter, controls the upload:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;: prepares the original colors so they receive the global effect before being displayed. Also prepares the palette if no effect has been selected yet.&lt;br /&gt;
* &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;: uploads the colors without the global effect and excludes that palette from it. Also updates SMW&#039;s buffers, which prevents palette corruption during the goal victory animation.&lt;br /&gt;
&lt;br /&gt;
To upload the same palette without the global effect, change only this define and keep the carry check:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!PaletteGlobalEffect = 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If effects are disabled in the installation, both options upload directly. When effects are enabled and you use &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, the system uploads the processed result; it does not display an unaffected palette for one frame first.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; uses &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt;, generated from the DynamicInfo&#039;s &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; section and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized to PascalCase by removing separators and capitalizing each word. In this case, &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; stays as written.&lt;br /&gt;
&lt;br /&gt;
To request another change during gameplay, set &amp;lt;code&amp;gt;!PaletteChangePending&amp;lt;/code&amp;gt; to 1 when your chosen condition is met. Do not set it every frame if the palette is unchanged. For a direct upload, carry set means the transfer was scheduled; with the global effect, it means the original colors were prepared, not that the result is already visible.&lt;br /&gt;
&lt;br /&gt;
The effect option applies to the entire 16-color palette. When uploading colors for a global effect, prepare all visible colors, as with the 15 in this example; do not change just a few colors expecting to preserve a base you have not prepared yet.&lt;br /&gt;
&lt;br /&gt;
If you use a fixed sprite palette from 8–F, set it aside first as described at the start of this article. These macros do not perform automatic assignment. To upload from an address, pointer, or table, see [[Dynamic_Xtreme_ASM_API#Uploading_colors_with_TransferPalette|Uploading colors with TransferPalette in the API]].&lt;br /&gt;
&lt;br /&gt;
== Changing the player&#039;s graphics ==&lt;br /&gt;
&lt;br /&gt;
This example switches between the original player and Geno when you press up. Its defines let you choose the graphics and four palettes: Mario, Luigi, Fire Mario, and Fire Luigi. It also updates the selected palette when the player&#039;s state changes.&lt;br /&gt;
&lt;br /&gt;
Requires &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;. Custom graphics must use the same pose layout as the originals; changing the source does not adapt a spritesheet with a different layout.&lt;br /&gt;
&lt;br /&gt;
The code uses the [[Dynamic_Xtreme_ASM_API#Player_and_Yoshi|player variables]] and macros [[Dynamic_Xtreme_ASM_API#Div_and_DivW|DivW]], [[Dynamic_Xtreme_ASM_API#TransferPaletteFromPointer|TransferPaletteFromPointer]], and [[Dynamic_Xtreme_ASM_API#TransferPaletteFromAddress|TransferPaletteFromAddress]]. Their API entries explain each call&#039;s parameters, registers, and results.&lt;br /&gt;
&lt;br /&gt;
Declare the following in &amp;lt;code&amp;gt;DynamicXtreme/Geno.dynamicinfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    Geno.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    GenoPal.bin&lt;br /&gt;
    GenoPalPlayer2.bin&lt;br /&gt;
    FireGenoPal.bin&lt;br /&gt;
    FireGenoPalPlayer2.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/Geno.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Choose two consecutive bytes of free RAM here.&lt;br /&gt;
!Last0D82 = RAM_LIBRE_JUGADOR_2_BYTES&lt;br /&gt;
&lt;br /&gt;
; Custom player graphics.&lt;br /&gt;
!PlayerGFXResource = !ResourceGeno&lt;br /&gt;
&lt;br /&gt;
; Palettes: player 1, player 2, and their fire variants.&lt;br /&gt;
!PlayerGFXPalette = !PaletteGenoPal&lt;br /&gt;
!PlayerGFXPalettePlayer2 = !PaletteGenoPalPlayer2&lt;br /&gt;
!PlayerGFXFirePalette = !PaletteFireGenoPal&lt;br /&gt;
!PlayerGFXFirePalettePlayer2 = !PaletteFireGenoPalPlayer2&lt;br /&gt;
&lt;br /&gt;
; Switch button: $08 = up.&lt;br /&gt;
!ChangeButton = $08&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA !Last0D82&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA !ButtonDown_BYETUDLR&lt;br /&gt;
    AND #!ChangeButton&lt;br /&gt;
    BNE .Change&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    CMP !Last0D82&lt;br /&gt;
    BNE .Reload&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
.Change&lt;br /&gt;
    LDA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    CMP.b #!GFX32Buffer&amp;gt;&amp;gt;16&lt;br /&gt;
    BEQ .ChooseGeno&lt;br /&gt;
    JMP .Mario&lt;br /&gt;
.ChooseGeno&lt;br /&gt;
    JMP .Geno&lt;br /&gt;
&lt;br /&gt;
.Reload&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    CMP.b #!GFX32Buffer&amp;gt;&amp;gt;16&lt;br /&gt;
    BNE .Geno&lt;br /&gt;
    JMP .Mario&lt;br /&gt;
&lt;br /&gt;
.Geno&lt;br /&gt;
    ; Get 0, 1, 2, or 3 based on the player and fire state.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    SEC&lt;br /&gt;
    SBC #!PlayerBasePalette&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    %DivW($01, $00, #$14)&lt;br /&gt;
&lt;br /&gt;
    ; Each address in GenoPals occupies three bytes.&lt;br /&gt;
    LDA !DivisionResult&lt;br /&gt;
    ASL&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC !DivisionResult&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    ; Keep the selected source and prepare colors 2-5.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l GenoPals,x&lt;br /&gt;
    STA $03&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$0002&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.l GenoPals+2,x&lt;br /&gt;
    STA $02&lt;br /&gt;
    STA $05&lt;br /&gt;
&lt;br /&gt;
    %TransferPaletteFromPointer($00, #$82, $0008, 0)&lt;br /&gt;
    BCS .ApplyGeno&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.ApplyGeno&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!PlayerGFXResource&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!PlayerGFXResource&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
&lt;br /&gt;
    ; The player routine uploads colors 6-F.&lt;br /&gt;
    LDA $03&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$000A&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA $05&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    JMP .ConfirmSelection&lt;br /&gt;
&lt;br /&gt;
.Mario&lt;br /&gt;
    %TransferPaletteFromAddress(!PlayerPaletteColor2To5, #$82, $0008, 0)&lt;br /&gt;
    BCS .ApplyMario&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.ApplyMario&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!GFX32Buffer&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    LDA.w #(!GFX32Buffer&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
.ConfirmSelection&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA !Last0D82&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
GenoPals:&lt;br /&gt;
    dl !PlayerGFXPalette&lt;br /&gt;
    dl !PlayerGFXPalettePlayer2&lt;br /&gt;
    dl !PlayerGFXFirePalette&lt;br /&gt;
    dl !PlayerGFXFirePalettePlayer2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What you can customize&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!PlayerGFXResource&amp;lt;/code&amp;gt;: custom character graphics.&lt;br /&gt;
* The four &amp;lt;code&amp;gt;!PlayerGFX...Palette...&amp;lt;/code&amp;gt; defines: palette addresses, in the order used by &amp;lt;code&amp;gt;GenoPals&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ChangeButton&amp;lt;/code&amp;gt;: button used to switch characters. Uses the controller bits &amp;lt;code&amp;gt;BYETUDLR&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; is up.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Last0D82&amp;lt;/code&amp;gt;: replace &amp;lt;code&amp;gt;RAM_LIBRE_JUGADOR_2_BYTES&amp;lt;/code&amp;gt; with two consecutive free RAM bytes. This stores the game&#039;s palette selection; neither byte may be used by other code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGeno&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteGenoPal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteGenoPalPlayer2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteFireGenoPal&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!PaletteFireGenoPalPlayer2&amp;lt;/code&amp;gt; are generated from the DynamicInfo and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names use PascalCase, with spaces, hyphens, and underscores removed and existing capitals preserved.&lt;br /&gt;
&lt;br /&gt;
Each palette file contains colors 1–F. Its first color is skipped to copy colors 2–5; the final ten start at &amp;lt;code&amp;gt;+$0A&amp;lt;/code&amp;gt; and are used by the player routine.&lt;br /&gt;
&lt;br /&gt;
Colors 2–5 are uploaded with &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, which also updates SMW&#039;s buffers. The example does not confirm a graphics change if that transfer is rejected. A pending player-state change is retried while it differs from &amp;lt;code&amp;gt;!Last0D82&amp;lt;/code&amp;gt;; if a button-requested change is rejected, press the button again.&lt;br /&gt;
&lt;br /&gt;
The code identifies the original player by the bank of &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt;. If you adapt it to switch between several custom characters in ROM, you will need another way to track the selected character.&lt;br /&gt;
&lt;br /&gt;
This example uploads the player&#039;s palette without the global effect. Changing a four-color upload&#039;s parameter to &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; is not enough to add an effect: you must prepare all visible colors of palette 8 and account for its special upload handling.&lt;br /&gt;
&lt;br /&gt;
== Applying a global palette effect ==&lt;br /&gt;
&lt;br /&gt;
These examples apply a fixed effect, cycle through effects, or run a transition that stops when finished. You can select each palette separately and include the fixed color. The cycle and transition examples also let you set the speed with &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
All three configure the [[Dynamic_Xtreme_ASM_API#Palettes_and_the_global_effect|global effect variables]] and the [[Dynamic_Xtreme_ASM_API#Fixed_color_and_the_first_palette_color|fixed color and first palette color variables]]. Their API entries explain each variable.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; files, &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; selects the effect type. Ratios range from 0 to 127, and &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt; values range from 0 to 31.&lt;br /&gt;
&lt;br /&gt;
=== Choosing the affected palettes ===&lt;br /&gt;
&lt;br /&gt;
In each example, set &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt; to 1 to include the corresponding palette or 0 to exclude it. &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; controls the fixed color, and &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt; includes color 0,0.&lt;br /&gt;
&lt;br /&gt;
The masks &amp;lt;code&amp;gt;!EnableBG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableSP&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!EnableColors&amp;lt;/code&amp;gt; are calculated from these settings. You do not need to edit them manually. In the current API, the lowest bit corresponds to the first palette in each group:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit value !! Background palette !! Sprite palette&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || 0 || 8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || 1 || 9&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || 2 || A&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || 3 || B&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || 4 || C&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || 5 || D&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || 6 || E&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; || 7 || F&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The fixed color and color 0,0 use &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt;: bits &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, respectively.&lt;br /&gt;
&lt;br /&gt;
For sprites with dynamic assignment, also configure the E bit in &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;. When using &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, its last parameter controls whether those palettes participate in the global effect. Avoid having other code overwrite the masks without accounting for this configuration.&lt;br /&gt;
&lt;br /&gt;
=== Applying a fixed effect ===&lt;br /&gt;
&lt;br /&gt;
This example applies the effect selected by &amp;lt;code&amp;gt;!PaletteEffetID&amp;lt;/code&amp;gt;. The configuration shown enables all palettes and the fixed color, and selects the last effect in &amp;lt;code&amp;gt;DecreaseSaturation&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Save the following in &amp;lt;code&amp;gt;DynamicXtreme/DecreaseSaturation.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 4, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 8, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 12, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 16, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 20, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 25, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 29, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 33, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 37, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 41, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 45, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 49, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 53, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 57, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 61, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 66, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 70, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 74, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 78, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 82, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 86, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 90, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 94, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 98, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 102, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 107, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 111, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 115, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 119, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 123, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 11}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file defines 32 effects. &amp;lt;code&amp;gt;EffectType = 11&amp;lt;/code&amp;gt; selects &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;Channel2 = 0&amp;lt;/code&amp;gt; reduces saturation, and &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; controls how much. The last effect uses 127, applying the full change.&lt;br /&gt;
&lt;br /&gt;
The ASM code is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/DecreaseSaturation.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = include the palette in the effect; 0 = exclude it.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 1&lt;br /&gt;
!P2 = 1&lt;br /&gt;
!P3 = 1&lt;br /&gt;
!P4 = 1&lt;br /&gt;
!P5 = 1&lt;br /&gt;
!P6 = 1&lt;br /&gt;
!P7 = 1&lt;br /&gt;
&lt;br /&gt;
!P8 = 1&lt;br /&gt;
!P9 = 1&lt;br /&gt;
!PA = 1&lt;br /&gt;
!PB = 1&lt;br /&gt;
!PC = 1&lt;br /&gt;
!PD = 1&lt;br /&gt;
!PE = 1&lt;br /&gt;
!PF = 1&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Effect applied when entering the level.&lt;br /&gt;
!PaletteEffetID = !PaletteEffectIDDecreaseSaturation31&lt;br /&gt;
&lt;br /&gt;
; Calculated masks: no manual changes needed.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What you can customize&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;: affected palettes.&lt;br /&gt;
* &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: whether these colors are affected.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteEffetID&amp;lt;/code&amp;gt;: selected effect. You can use any ID generated from your effects file, not just this example&#039;s final effect.&lt;br /&gt;
&lt;br /&gt;
Defines &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation0&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation31&amp;lt;/code&amp;gt; are generated from the &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names use PascalCase, with spaces, hyphens, and underscores removed and existing capitals preserved.&lt;br /&gt;
&lt;br /&gt;
The effect is selected in &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;; you do not need to repeat this every frame. To remove it, write 0 to the global effect ID and leave the palettes enabled so the system restores their original colors:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cycling through effects ===&lt;br /&gt;
&lt;br /&gt;
This example runs through a sequence of effects and returns to the first. You can configure the speed, first and last IDs, and affected palettes. The settings shown include only palette 0 and the fixed color.&lt;br /&gt;
&lt;br /&gt;
Save the following in &amp;lt;code&amp;gt;DynamicXtreme/Hue.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 1, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 2, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 3, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 4, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 5, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 6, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 7, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 8, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 9, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 10, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 11, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 12, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 13, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 14, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 15, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 16, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 17, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 18, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 19, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 20, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 21, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 22, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 23, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 24, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 25, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 26, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 27, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 28, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 29, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 30, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 31, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 31, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file defines 32 hue effects. &amp;lt;code&amp;gt;EffectType = 9&amp;lt;/code&amp;gt; selects &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Ratio1 = 127&amp;lt;/code&amp;gt; fully applies the selected hue.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Hue.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = include the palette in the effect; 0 = exclude it.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 0&lt;br /&gt;
!P2 = 0&lt;br /&gt;
!P3 = 0&lt;br /&gt;
!P4 = 0&lt;br /&gt;
!P5 = 0&lt;br /&gt;
!P6 = 0&lt;br /&gt;
!P7 = 0&lt;br /&gt;
&lt;br /&gt;
!P8 = 0&lt;br /&gt;
!P9 = 0&lt;br /&gt;
!PA = 0&lt;br /&gt;
!PB = 0&lt;br /&gt;
!PC = 0&lt;br /&gt;
!PD = 0&lt;br /&gt;
!PE = 0&lt;br /&gt;
!PF = 0&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Allowed values: $00, $01, $03, $07, $0F, $1F, $3F, $7F, and $FF.&lt;br /&gt;
!Delay = $03&lt;br /&gt;
&lt;br /&gt;
!StartingPaletteEffetID = !PaletteEffectIDHue0&lt;br /&gt;
!EndPaletteEffetID = !PaletteEffectIDHue31&lt;br /&gt;
&lt;br /&gt;
; Calculated masks: no manual changes needed.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #!Delay&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!EndPaletteEffetID&lt;br /&gt;
    BCS .Restart&lt;br /&gt;
    INC A&lt;br /&gt;
    BRA .Store&lt;br /&gt;
.Restart&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
.Store&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What you can customize&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: affected colors.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;: interval between changes. &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; changes every frame, &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; every two frames, &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; every four, and &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; every eight. Use only the values listed in the comment.&lt;br /&gt;
* &amp;lt;code&amp;gt;!StartingPaletteEffetID&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!EndPaletteEffetID&amp;lt;/code&amp;gt;: first and last effects in the cycle. They must form a consecutive ID range, with the start less than or equal to the end.&lt;br /&gt;
&lt;br /&gt;
The cycle displays the last ID before returning to the first. It uses &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; to time changes, so the first interval depends on that counter&#039;s value when entering the level. To stop it while the action is frozen, also check &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt; at the start of &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Defines &amp;lt;code&amp;gt;!PaletteEffectIDHue0&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;!PaletteEffectIDHue31&amp;lt;/code&amp;gt; are generated from the &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized to PascalCase by removing separators; here, &amp;lt;code&amp;gt;Hue&amp;lt;/code&amp;gt; stays unchanged.&lt;br /&gt;
&lt;br /&gt;
=== Running a transition that stops when complete ===&lt;br /&gt;
&lt;br /&gt;
This example advances from the first effect to the last and keeps the final result. You can configure the affected palettes, fixed color, speed, and ID range.&lt;br /&gt;
&lt;br /&gt;
Save the following in &amp;lt;code&amp;gt;DynamicXtreme/Night.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 0, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 4, &amp;quot;Ratio2&amp;quot;: 4, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 8, &amp;quot;Ratio2&amp;quot;: 8, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 12, &amp;quot;Ratio2&amp;quot;: 12, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 16, &amp;quot;Ratio2&amp;quot;: 16, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 20, &amp;quot;Ratio2&amp;quot;: 20, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 25, &amp;quot;Ratio2&amp;quot;: 25, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 29, &amp;quot;Ratio2&amp;quot;: 29, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 33, &amp;quot;Ratio2&amp;quot;: 33, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 37, &amp;quot;Ratio2&amp;quot;: 37, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 41, &amp;quot;Ratio2&amp;quot;: 41, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 45, &amp;quot;Ratio2&amp;quot;: 45, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 49, &amp;quot;Ratio2&amp;quot;: 49, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 53, &amp;quot;Ratio2&amp;quot;: 53, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 57, &amp;quot;Ratio2&amp;quot;: 57, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 61, &amp;quot;Ratio2&amp;quot;: 61, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 66, &amp;quot;Ratio2&amp;quot;: 66, &amp;quot;EffectType&amp;quot;: 2}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The transition has 17 steps. &amp;lt;code&amp;gt;EffectType = 2&amp;lt;/code&amp;gt; selects &amp;lt;code&amp;gt;MixRG&amp;lt;/code&amp;gt;: it reduces red and green without changing blue. Ratios increase from 0 to 66 to darken the colors gradually without completely removing red and green.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Night.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = include the palette in the effect; 0 = exclude it.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 1&lt;br /&gt;
!P2 = 1&lt;br /&gt;
!P3 = 1&lt;br /&gt;
!P4 = 1&lt;br /&gt;
!P5 = 1&lt;br /&gt;
!P6 = 1&lt;br /&gt;
!P7 = 1&lt;br /&gt;
&lt;br /&gt;
!P8 = 1&lt;br /&gt;
!P9 = 1&lt;br /&gt;
!PA = 1&lt;br /&gt;
!PB = 1&lt;br /&gt;
!PC = 1&lt;br /&gt;
!PD = 1&lt;br /&gt;
!PE = 1&lt;br /&gt;
!PF = 1&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Allowed values: $00, $01, $03, $07, $0F, $1F, $3F, $7F, and $FF.&lt;br /&gt;
!Delay = $03&lt;br /&gt;
&lt;br /&gt;
!StartingPaletteEffetID = !PaletteEffectIDNight0&lt;br /&gt;
!EndPaletteEffetID = !PaletteEffectIDNight16&lt;br /&gt;
&lt;br /&gt;
; Calculated masks: no manual changes needed.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #!Delay&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!EndPaletteEffetID&lt;br /&gt;
    BCS .Finished&lt;br /&gt;
    INC A&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
.Finished&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What you can customize&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: affected colors.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;: interval between changes, using the same allowed values as the cycle example.&lt;br /&gt;
* &amp;lt;code&amp;gt;!StartingPaletteEffetID&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!EndPaletteEffetID&amp;lt;/code&amp;gt;: first and last effects. IDs must be consecutive and in ascending order.&lt;br /&gt;
&lt;br /&gt;
Defines &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;!PaletteEffectIDNight16&amp;lt;/code&amp;gt; are generated from &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; and written to &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names use PascalCase with separators removed; here, &amp;lt;code&amp;gt;Night&amp;lt;/code&amp;gt; stays unchanged.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This example moves between mixing effects. To transition toward another complete palette, use &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt;, described in [[Dynamic_Xtreme_files_and_formats#Palette_transitions|Files and formats]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_sprite_creation_guide&amp;diff=21395</id>
		<title>Dynamic Xtreme sprite creation guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_sprite_creation_guide&amp;diff=21395"/>
		<updated>2026-10-25T21:56:50Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: Created page with &amp;quot;{{Select Language|Dynamic_Xtreme_sprite_creation_guide}}  This article explains how to create dynamic sprites using Dynamic Xtreme and PIXI.  The guide covers the complete process: preparing graphics, defining poses, including the necessary files in the sprite, and using the system to load and draw its poses on screen.  For questions about a call&amp;#039;s registers, parameters, or return values, see the ASM API. The relevant sections of this guide lin...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_sprite_creation_guide}}&lt;br /&gt;
&lt;br /&gt;
This article explains how to create dynamic sprites using Dynamic Xtreme and PIXI.&lt;br /&gt;
&lt;br /&gt;
The guide covers the complete process: preparing graphics, defining poses, including the necessary files in the sprite, and using the system to load and draw its poses on screen.&lt;br /&gt;
&lt;br /&gt;
For questions about a call&#039;s registers, parameters, or return values, see the [[Dynamic_Xtreme_ASM_API|ASM API]]. The relevant sections of this guide link directly to the corresponding calls.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
To follow this guide, you need:&lt;br /&gt;
&lt;br /&gt;
* [https://www.smwcentral.net/?p=section&amp;amp;s=tools&amp;amp;f%5Bname%5D=PIXI PIXI] installed and configured to insert sprites into your ROM.&lt;br /&gt;
* Dynamic Xtreme installed and configured. If you have not done this yet, see the [[Dynamic_Xtreme_Quick_Start|Quick Start guide]].&lt;br /&gt;
&lt;br /&gt;
== Files used by a dynamic sprite ==&lt;br /&gt;
&lt;br /&gt;
In addition to the files normally used by PIXI, a dynamic sprite needs:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Graphics file (*.bin):&#039;&#039;&#039; the graphics for the sprite&#039;s poses.&lt;br /&gt;
* &#039;&#039;&#039;DynamicInfo (*.dynamicinfo):&#039;&#039;&#039; specifies which graphics the sprite uses and how they are divided into poses.&lt;br /&gt;
* &#039;&#039;&#039;DrawInfo (*.drawinfo):&#039;&#039;&#039; the information needed to draw the poses.&lt;br /&gt;
* &#039;&#039;&#039;ASM file (*.asm):&#039;&#039;&#039; the sprite&#039;s code, which uses the resources above.&lt;br /&gt;
&lt;br /&gt;
One possible arrangement is to keep the Dynamic Xtreme files with the PIXI resource itself. For example, a normal sprite could use this structure:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PIXI/&lt;br /&gt;
└── sprites/&lt;br /&gt;
    └── MySprite/&lt;br /&gt;
        ├── MySprite.asm&lt;br /&gt;
        ├── MySprite.json&lt;br /&gt;
        └── DynamicXtreme/&lt;br /&gt;
            ├── MySprite.bin&lt;br /&gt;
            ├── MySprite.dynamicinfo&lt;br /&gt;
            └── MySprite.drawinfo&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep the ASM and configuration file in the sprite&#039;s main folder. Store the graphics, DynamicInfo, and DrawInfo in the &amp;lt;code&amp;gt;DynamicXtreme&amp;lt;/code&amp;gt; subfolder.&lt;br /&gt;
&lt;br /&gt;
In this arrangement, the sprite&#039;s main ASM must include DynamicInfo and DrawInfo with these directives:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MySprite.dynamicinfo&amp;quot;&lt;br /&gt;
;#incdri &amp;quot;DynamicXtreme/MySprite.drawinfo&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Paths are relative to the ASM containing the directives. For a cluster sprite, extended sprite, or another type supported by PIXI, the whole resource folder can be arranged the same way inside the corresponding PIXI folder.&lt;br /&gt;
&lt;br /&gt;
You can also use Dynamic Xtreme&#039;s traditional folders. Put &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;DynamicInfos&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;DrawInfos&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;*.bin&amp;lt;/code&amp;gt; graphics in &amp;lt;code&amp;gt;DynamicResources&amp;lt;/code&amp;gt;. Dynamic Xtreme discovers files stored this way directly, so the sprite does not need &amp;lt;code&amp;gt;;#incdyn&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;;#incdri&amp;lt;/code&amp;gt; directives.&lt;br /&gt;
&lt;br /&gt;
The first option makes it easier to distribute the sprite with all its resources in one folder; the second retains Dynamic Xtreme&#039;s traditional organization. For each format&#039;s structure and rules, see [[Dynamic_Xtreme_files_and_formats|Dynamic Xtreme files and formats]].&lt;br /&gt;
&lt;br /&gt;
During installation, Dynamic Xtreme generates the defines used by the sprite code and saves them in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. This table summarizes the names used in the guide:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Example define !! Source !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt;&lt;br /&gt;
| Horizontal bounds of the poses in &amp;lt;code&amp;gt;MySprite.drawinfo&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Configure the horizontal RenderBox distance in INIT.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt;&lt;br /&gt;
| Vertical bounds of the poses in &amp;lt;code&amp;gt;MySprite.drawinfo&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Configure the vertical RenderBox distance in INIT.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; list in &amp;lt;code&amp;gt;MySprite.dynamicinfo&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Tell palette assignment which table to use.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt;&lt;br /&gt;
| The first pose in &amp;lt;code&amp;gt;MySprite.bin&amp;lt;/code&amp;gt;, declared under &amp;lt;code&amp;gt;PosesGraphics&amp;lt;/code&amp;gt; in DynamicInfo.&lt;br /&gt;
| Request that pose&#039;s graphics through &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; suffix identifies the graphics file&#039;s first pose; &amp;lt;code&amp;gt;003&amp;lt;/code&amp;gt; identifies its fourth.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;lt;code&amp;gt;Frame0&amp;lt;/code&amp;gt; pose declared in &amp;lt;code&amp;gt;MySprite.drawinfo&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Select the pose drawn by &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt;&lt;br /&gt;
| The first effect in &amp;lt;code&amp;gt;MyEffect.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Select the palette effect to apply.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Names are normalized by removing separators and capitalizing each word&#039;s first letter: for example, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Always check the exact generated names in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; the guide also repeats their origin beside each use.&lt;br /&gt;
&lt;br /&gt;
== Sprite structure ==&lt;br /&gt;
&lt;br /&gt;
A dynamic sprite retains the usual PIXI sprite structure, but must prepare Dynamic Xtreme&#039;s variables and organize its main routine according to whether it is within drawing distance of the screen.&lt;br /&gt;
&lt;br /&gt;
The structure used in this guide has these parts:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;INIT:&#039;&#039;&#039; initializes the sprite variables and Dynamic Xtreme state.&lt;br /&gt;
* &#039;&#039;&#039;Short routine:&#039;&#039;&#039; runs the logic that must continue even when the sprite is outside drawing distance.&lt;br /&gt;
* &#039;&#039;&#039;Long routine:&#039;&#039;&#039; handles work needed only within drawing distance, such as requesting and drawing the pose.&lt;br /&gt;
&lt;br /&gt;
=== Include the sprite type defines ===&lt;br /&gt;
&lt;br /&gt;
Before the sprite&#039;s code, include the defines file for its resource type:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt; for normal sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; for cluster sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; for extended sprites.&lt;br /&gt;
&lt;br /&gt;
For example, if a normal sprite&#039;s ASM is in a subfolder of &amp;lt;code&amp;gt;sprites&amp;lt;/code&amp;gt;, the include can be written as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
incsrc &amp;quot;../NormalSpriteDefines.asm&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The path is always relative to the sprite ASM, so adjust it to the resource&#039;s folder structure. This file supplies table and routine aliases for the sprite type. Names such as &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; therefore select the correct implementation for a normal, cluster, or extended sprite.&lt;br /&gt;
&lt;br /&gt;
=== INIT ===&lt;br /&gt;
&lt;br /&gt;
For normal sprites, &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; must set the &amp;lt;code&amp;gt;RenderBox&amp;lt;/code&amp;gt; distances, assign initial values, and invalidate any previous state left in the same PIXI slot.&lt;br /&gt;
&lt;br /&gt;
The following normal sprite example starts at pose 0 and obtains its version and initial flip from the PIXI configuration:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
print &amp;quot;INIT &amp;quot;,pc&lt;br /&gt;
    LDA.b #!RenderBoxXDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderXDistanceOutOfScreen,x&lt;br /&gt;
    LDA.b #!RenderBoxYDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderYDistanceOutOfScreen,x&lt;br /&gt;
&lt;br /&gt;
    LDA !ExtraBits,x&lt;br /&gt;
    AND #$04&lt;br /&gt;
    LSR&lt;br /&gt;
    LSR&lt;br /&gt;
    STA !GlobalFlip,x&lt;br /&gt;
&lt;br /&gt;
    LDA !ExtraByte1,x&lt;br /&gt;
    AND #$0F&lt;br /&gt;
    STA !Version,x&lt;br /&gt;
&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    STA !PoseIndex,x&lt;br /&gt;
    STA !LocalFlip,x&lt;br /&gt;
    STA !LastFlip,x&lt;br /&gt;
&lt;br /&gt;
    LDA #$FF&lt;br /&gt;
    STA !Palette,x&lt;br /&gt;
    STA !LastPoseIndex,x&lt;br /&gt;
    STA !LastPoseHashIndex,x&lt;br /&gt;
    STA !LastVersion,x&lt;br /&gt;
&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each variable in the example has a specific role:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen&amp;lt;/code&amp;gt; store the distances used by &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; to decide whether the sprite is still close enough to the screen to draw. &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; are generated from DrawInfo and available in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. The resource name is normalized by removing separators such as spaces and underscores and capitalizing each word&#039;s first letter. For example, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;my sprite&amp;lt;/code&amp;gt; become &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; selects the desired dynamic pose within DynamicInfo. Zero selects the resource&#039;s first pose. An animation routine can assign another value before requesting graphics.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt; identifies the sprite&#039;s current variant. A version can change its palette, graphics, or behavior. Normal sprites commonly take it from the low four bits of &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt;, allowing up to 16 versions to be selected in Lunar Magic.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip&amp;lt;/code&amp;gt; is the sprite&#039;s overall flip. Normal sprites can obtain it from the extra bit: 0 keeps the original orientation and 1 applies the initial flip. &amp;lt;code&amp;gt;!LocalFlip&amp;lt;/code&amp;gt; adds a flip for the current pose. Dynamic Xtreme combines both and stores the effective drawing flip in &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt; stores the currently assigned palette. It starts at &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; because no valid palette has been assigned yet.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; stores the last pose Dynamic Xtreme successfully obtained, and &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; stores its VRAM cache slot. Both start at &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; because no pose is available yet.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt; stores the version previously processed by palette management. Starting it at &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; ensures the first version is processed even when &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt; starts at 0.&lt;br /&gt;
&lt;br /&gt;
If a sprite uses several DrawInfo files, the distances must cover all its graphics. Check each DrawInfo&#039;s generated values in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; and use the largest horizontal and vertical distances. For example, if the head and body use separate DrawInfo files, using only the head&#039;s distances may stop drawing the sprite while part of its body is still on screen.&lt;br /&gt;
&lt;br /&gt;
Values marked &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; represent invalid states. Besides indicating that no palette or pose is available yet, they prevent reuse of data left by a sprite that previously occupied the same PIXI slot.&lt;br /&gt;
&lt;br /&gt;
==== Initializing cluster and extended sprites ====&lt;br /&gt;
&lt;br /&gt;
Cluster and extended sprites have no dedicated &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; routine. To initialize them once, reserve one of their tables, such as &amp;lt;code&amp;gt;!ClusterMiscTable1&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;!ExtendedMiscTable1&amp;lt;/code&amp;gt;, and give it a name such as &amp;lt;code&amp;gt;!Started&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!Started = !ClusterMiscTable1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When creating the sprite, set &amp;lt;code&amp;gt;!Started&amp;lt;/code&amp;gt; to 0 using the new cluster or extended sprite&#039;s index. The slot may have been used before and could still hold another sprite&#039;s value.&lt;br /&gt;
&lt;br /&gt;
At the start of &amp;lt;code&amp;gt;SpriteCode&amp;lt;/code&amp;gt;, before &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;, check this variable:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpriteCode:&lt;br /&gt;
    LDA !Started,x&lt;br /&gt;
    BNE +&lt;br /&gt;
    JSR Start&lt;br /&gt;
    RTS&lt;br /&gt;
+&lt;br /&gt;
    !RenderBox&lt;br /&gt;
    ; Rest of the sprite code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start&amp;lt;/code&amp;gt; contains the initialization normally done in a normal sprite&#039;s &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt;. At the end, it sets &amp;lt;code&amp;gt;!Started&amp;lt;/code&amp;gt; to 1 so it does not run again on later frames:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Start:&lt;br /&gt;
    ; Initialize the sprite here&lt;br /&gt;
&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !Started,x&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because &amp;lt;code&amp;gt;Start&amp;lt;/code&amp;gt; is called with &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;, it must end with &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;. The code creating the cluster or extended sprite must also prepare inherited data, such as &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;!GlobalFlip&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== PaletteOption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; controls the requested palette and whether it receives the global palette effect. Its format is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EPPP----&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; determines whether the palette receives the global effect: 0 excludes it and 1 enables it.&lt;br /&gt;
* &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; represents a palette from 8 to F: &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; selects palette 8 and &amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt; selects palette F.&lt;br /&gt;
* The low four bits are not part of &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
With automatic assignment, &amp;lt;code&amp;gt;PPP = 000&amp;lt;/code&amp;gt; searches all eight palettes for a free slot; a nonzero &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; value limits the search to palettes 8–B, and &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; limits it to C–F. With manual assignment, &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; directly selects the palette.&lt;br /&gt;
&lt;br /&gt;
For normal sprites, &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; directly uses &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt;. The remaining four bits commonly select the sprite version, giving the whole byte this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EPPPVVVV&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;EPPP&amp;lt;/code&amp;gt; contains the palette options described above.&lt;br /&gt;
* &amp;lt;code&amp;gt;VVVV&amp;lt;/code&amp;gt; selects one of 16 sprite versions, from 0 to 15.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; directly uses the high four bits, while &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; copies the low four bits to &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt;. You do not need to copy &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; into another table.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignmentOption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; determines how the sprite&#039;s palette is assigned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--AA----&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 00&amp;lt;/code&amp;gt;: &#039;&#039;&#039;automatic assignment&#039;&#039;&#039;. Dynamic Xtreme finds a slot allowed by &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; and loads the palette dynamically.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 01&amp;lt;/code&amp;gt;: &#039;&#039;&#039;manual assignment&#039;&#039;&#039;. &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; specifies the exact slot, and Dynamic Xtreme loads the palette dynamically.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 10&amp;lt;/code&amp;gt;: &#039;&#039;&#039;manual assignment without upload&#039;&#039;&#039;. The sprite uses the palette already in the level; Dynamic Xtreme does not load a new one.&lt;br /&gt;
&lt;br /&gt;
For normal sprites, &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; directly uses &amp;lt;code&amp;gt;!ExtraProp2,x&amp;lt;/code&amp;gt;. Set the mode through bits 5 and 4 of Extra Property Byte 2; it does not need to be copied into another table in &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For cluster and extended sprites, set &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; manually when they are created. Normally, copy the creating sprite&#039;s assignment mode. When copying &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;, clear the low four bits because they contain a normal sprite&#039;s version, not palette options.&lt;br /&gt;
&lt;br /&gt;
If the spawned sprite uses the same palette as its parent, copy its &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; after clearing the low four bits. If it uses a different palette and the parent uses automatic assignment, keep the same search range. For manual assignment, with or without upload, add &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; to the masked value to select the next palette.&lt;br /&gt;
&lt;br /&gt;
In the last case, the parent cannot use palette F because the spawned sprite needs the next palette. Configure the parent with a palette from 8 to E.&lt;br /&gt;
&lt;br /&gt;
Besides these variables, &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; can initialize any tables needed for the sprite&#039;s behavior.&lt;br /&gt;
&lt;br /&gt;
=== SpriteCode ===&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme_ASM_API#RenderBox|RenderBox]] in the API for its inputs and result.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SpriteCode&amp;lt;/code&amp;gt; starts with &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;. It returns carry set when the sprite is within drawing distance and clear when it is outside. This selects the short or long routine.&lt;br /&gt;
&lt;br /&gt;
A basic structure is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpriteCode:&lt;br /&gt;
    !RenderBox&lt;br /&gt;
    BCS .LongRoutine&lt;br /&gt;
&lt;br /&gt;
.ShortRoutine&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    %SubOffScreen()&lt;br /&gt;
    ; Put your sprite&#039;s logic here&lt;br /&gt;
RTS&lt;br /&gt;
&lt;br /&gt;
.LongRoutine&lt;br /&gt;
    JSR PaletteManagement&lt;br /&gt;
    BCC ..Return&lt;br /&gt;
&lt;br /&gt;
    JSR PoseManagement&lt;br /&gt;
    BCC ..Return&lt;br /&gt;
&lt;br /&gt;
    JSR Draw&lt;br /&gt;
    ; Put your sprite&#039;s logic here&lt;br /&gt;
..Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Short routine ====&lt;br /&gt;
&lt;br /&gt;
The short routine runs when the sprite is outside the area checked by &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;. Run only the core logic needed to maintain its behavior, without requesting dynamic graphics, processing its palette, or drawing it. The exact contents depend on the sprite and may include movement, state, timers, interactions, or animation.&lt;br /&gt;
&lt;br /&gt;
For normal sprites, calling &amp;lt;code&amp;gt;%SubOffScreen()&amp;lt;/code&amp;gt; here is recommended. It takes a value from 0 to 7 in A to select the offscreen removal setting; the example uses the usual value, 0. This lets PIXI remove the sprite when it gets far enough offscreen, without running this check in the more expensive drawing path.&lt;br /&gt;
&lt;br /&gt;
==== Long routine ====&lt;br /&gt;
&lt;br /&gt;
The long routine runs when the sprite is within drawing distance. It handles the complete process: palette management, requesting the dynamic pose or updating its last-use record if it is already in VRAM to protect it from replacement, drawing the sprite, and finally running the same core logic as the short routine.&lt;br /&gt;
&lt;br /&gt;
There is no need to call &amp;lt;code&amp;gt;%SubOffScreen()&amp;lt;/code&amp;gt; again in the long routine. &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; has already determined that the sprite is within drawing distance, so the check would be redundant.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;PaletteManagement&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PoseManagement&amp;lt;/code&amp;gt; return carry set when a usable resource exists. If either returns carry clear, the example branches to &amp;lt;code&amp;gt;..Return&amp;lt;/code&amp;gt; and ends the routine. The sprite is not drawn and the subsequent logic is not run during that frame.&lt;br /&gt;
&lt;br /&gt;
The following sections develop the palette, pose, and drawing routines. Their names are just one way to organize the code and can be changed to suit the sprite.&lt;br /&gt;
&lt;br /&gt;
== Palette management ==&lt;br /&gt;
&lt;br /&gt;
=== Load a dynamic palette ===&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme_ASM_API#PaletteAssignment|PaletteAssignment]] in the API for details.&lt;br /&gt;
&lt;br /&gt;
To use palette assignment in a normal sprite, configure at least one Extra Byte in its &amp;lt;code&amp;gt;*.cfg&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;*.json&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extra Byte 1:&#039;&#039;&#039; supplies &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;; in this guide&#039;s example, its low four bits select &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Extra Property Byte 2:&#039;&#039;&#039; sets &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; through bits 5 and 4: &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; for automatic assignment, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; for manual assignment, and &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt; for manual assignment without upload. These bits correspond to &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;; the remaining bits can serve other sprite options.&lt;br /&gt;
&lt;br /&gt;
Load a dynamic palette through &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;. Simply load the resource&#039;s generated palette table offset into 16-bit A:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignment&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; is generated from the palettes declared in DynamicInfo and appears in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. The DynamicInfo name is normalized by removing spaces, underscores, and other separators and capitalizing each word&#039;s first letter. For example, &amp;lt;code&amp;gt;my_sprite.dynamicinfo&amp;lt;/code&amp;gt; produces &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; uses &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt; to select a table entry: version 0 uses the first palette, version 1 the second, and so on. It also uses &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; to decide where and how to assign it.&lt;br /&gt;
&lt;br /&gt;
The routine returns carry set when a usable palette exists and clear when one could not yet be obtained. &amp;lt;code&amp;gt;SpriteCode&amp;lt;/code&amp;gt; therefore checks carry before loading poses and drawing. Call &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; every frame of the long routine to keep the assignment while the sprite uses it.&lt;br /&gt;
&lt;br /&gt;
=== Select a palette without changing the sprite version ===&lt;br /&gt;
&lt;br /&gt;
A sprite&#039;s palette can change without changing its version or behavior. For example, it can switch between its normal palette and a second palette during an animation or temporary state. Keeping both palettes as separate resources also lets other sprites reuse the second one.&lt;br /&gt;
&lt;br /&gt;
Because &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; selects its entry using &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt;, temporarily save the sprite&#039;s logical version, set the desired palette index, and restore the original version afterward:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    LDA !Version,x&lt;br /&gt;
    PHA&lt;br /&gt;
&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !Version,x&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignment&lt;br /&gt;
&lt;br /&gt;
    PLA&lt;br /&gt;
    STA !Version,x&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here, &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; uses table entry 2, but the sprite&#039;s behavior keeps its original version. This separates palette selection from the character&#039;s logical variant. &amp;lt;code&amp;gt;PLA&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;STA&amp;lt;/code&amp;gt; do not change carry, so &amp;lt;code&amp;gt;PaletteManagement&amp;lt;/code&amp;gt; still returns the correct &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; result.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; is generated from DynamicInfo and stored in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. The same name normalization applies: remove separators and capitalize each word&#039;s first letter, so &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Concatenate a local effect with the global effect ===&lt;br /&gt;
&lt;br /&gt;
See the API entries for [[Dynamic_Xtreme_ASM_API#PaletteAssignmentNoUpload|PaletteAssignmentNoUpload]], [[Dynamic_Xtreme_ASM_API#ConcatenateRGBPaletteEffectToGlobal|ConcatenateRGBPaletteEffectToGlobal]], and [[Dynamic_Xtreme_ASM_API#ConcatenateHSLPaletteEffectToGlobal|ConcatenateHSLPaletteEffectToGlobal]].&lt;br /&gt;
&lt;br /&gt;
When a palette needs its own effect combined with the global palette effect, use &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; followed by &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    PHY&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #$06&lt;br /&gt;
    TAY&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA PaletteEffects,y&lt;br /&gt;
&lt;br /&gt;
    PLY&lt;br /&gt;
    !ConcatenateRGBPaletteEffectToGlobal&lt;br /&gt;
&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&lt;br /&gt;
PaletteEffects:&lt;br /&gt;
    dw !PaletteEffectIDMyEffect0&lt;br /&gt;
    dw !PaletteEffectIDMyEffect1&lt;br /&gt;
    dw !PaletteEffectIDMyEffect2&lt;br /&gt;
    dw !PaletteEffectIDMyEffect3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; assigns the palette and prepares its base address without performing the final upload. It also leaves information in Y that tells the concatenation routine whether the effect must be rebuilt.&lt;br /&gt;
&lt;br /&gt;
This example uses &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;, Super Mario World&#039;s main frame counter, to select one of four effects. Since Y is temporarily needed to read &amp;lt;code&amp;gt;PaletteEffects&amp;lt;/code&amp;gt;, it is first saved with &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; and restored with &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt;. Pass that restored value unchanged to the concatenation routine.&lt;br /&gt;
&lt;br /&gt;
Before concatenation, X must contain &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, which already represents the index required by the routine. A must contain the 16-bit local effect ID. Here, Y indexes a table to load the ID, but the ID is ultimately passed in A.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; comes from DynamicInfo and is stored in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;!PaletteEffectIDMyEffectX&amp;lt;/code&amp;gt; defines are generated from a &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; during installation and stored in the same file. In both cases, names are normalized by removing spaces, underscores, and other separators and capitalizing each word&#039;s first letter. For example, &amp;lt;code&amp;gt;my_effect.paleffect&amp;lt;/code&amp;gt; produces &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is the effect index within the collection.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; for RGB effects such as &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt; for HSL effects such as &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;. To combine local and global effects, enable bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; of &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;. The routine handles any conversions needed when the two effects use different color spaces. See [[Dynamic_Xtreme_files_and_formats#Effect_types|Effect types]] for each effect&#039;s color space.&lt;br /&gt;
&lt;br /&gt;
Concatenation returns carry set when a usable result exists, including a previous result kept as a fallback, and clear when that palette has no valid result yet. Preserve this carry so &amp;lt;code&amp;gt;SpriteCode&amp;lt;/code&amp;gt; can decide whether to continue drawing.&lt;br /&gt;
&lt;br /&gt;
== Dynamic pose management ==&lt;br /&gt;
&lt;br /&gt;
Request dynamic poses with &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;. These routines search the VRAM cache and request a load if the pose is not available. Call them every frame of the long routine to keep the sprite&#039;s pose in use.&lt;br /&gt;
&lt;br /&gt;
=== Upload ===&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme_ASM_API#Upload|Upload]] in the API for details.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; takes the resource&#039;s base dynamic ID in 16-bit A and adds &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    !Upload&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here, &amp;lt;code&amp;gt;!PoseIndex = 0&amp;lt;/code&amp;gt; requests the first pose, 1 the next, and so on. This lets the animation routine change only &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; while &amp;lt;code&amp;gt;PoseManagement&amp;lt;/code&amp;gt; keeps the same base ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; is generated from DynamicInfo during installation and appears in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Names are normalized by removing spaces, underscores, and other separators and capitalizing each word&#039;s first letter. For example, &amp;lt;code&amp;gt;my_sprite.dynamicinfo&amp;lt;/code&amp;gt; produces &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; returns carry set when a usable pose exists. This can be the pose requested this frame or the sprite&#039;s last valid pose, used as a fallback while the new one cannot yet be loaded. Carry is clear only when the sprite has no usable pose.&lt;br /&gt;
&lt;br /&gt;
When a request succeeds, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; stores the available pose and &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; its VRAM cache entry. Drawing must therefore use the last available pose&#039;s state rather than assume &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; has been loaded.&lt;br /&gt;
&lt;br /&gt;
=== UploadWithoutPoseOffset ===&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme_ASM_API#UploadWithoutPoseOffset|UploadWithoutPoseOffset]] in the API for details.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; also takes a dynamic ID in 16-bit A but uses it directly, without adding &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite003&lt;br /&gt;
    !UploadWithoutPoseOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use this variant when your code has already selected the exact dynamic ID, for example through a table or condition. Carry has the same meaning as in &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;: set when a usable pose exists, clear when none is available.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite003&amp;lt;/code&amp;gt; is also generated from DynamicInfo and stored in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. The same CamelCase-style normalization removes separators and capitalizes each word&#039;s first letter.&lt;br /&gt;
&lt;br /&gt;
Currently, the normal and cluster sprite defines publish &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;. Extended sprites must use &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; until their defines file publishes this alias.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; defines belong to dynamic loading. Do not confuse them with DrawInfo&#039;s &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt; defines, which are used to draw the pose.&lt;br /&gt;
&lt;br /&gt;
== Drawing poses on screen ==&lt;br /&gt;
&lt;br /&gt;
Once &amp;lt;code&amp;gt;PoseManagement&amp;lt;/code&amp;gt; obtains a usable pose, draw it with &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt;. Both use the sprite position, flip, palette, and dynamic pose state kept by Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Before either call, prepare:&lt;br /&gt;
&lt;br /&gt;
* The drawing pose ID in 16-bit A.&lt;br /&gt;
* Additional properties in &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt;, using the &amp;lt;code&amp;gt;YXCC----&amp;lt;/code&amp;gt; format.&lt;br /&gt;
* The highest allowed tile priority in &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; accepts:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;: maximum priority.&lt;br /&gt;
* &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt;: high priority.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;: the sprite type&#039;s own priority.&lt;br /&gt;
* &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;: lowest priority.&lt;br /&gt;
&lt;br /&gt;
=== DXDraw ===&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme_ASM_API#DXDraw|DXDraw]] in the API for details.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; draws the pose using the sprite&#039;s normal position as its origin. A basic drawing routine is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDraw&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; is added to the first drawing ID to select the pose actually available. Use &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;: while a new pose is unavailable, Dynamic Xtreme may keep the previous pose as a fallback.&lt;br /&gt;
&lt;br /&gt;
This example assumes DrawInfo poses follow the same order as DynamicInfo poses. If they differ, convert &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; to the matching drawing ID, for example using a table.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; is generated from DrawInfo during installation and appears in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Generated names remove spaces, underscores, and other separators and capitalize each word&#039;s first letter. For example, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; produces &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt; identifies a drawing pose declared in DrawInfo. Do not confuse it with DynamicInfo&#039;s &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt;, used by &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; to request dynamic graphics.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; combines &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt;, the assigned palette, and the pose&#039;s own properties. It also uses &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; to locate graphics in the VRAM cache. If this is &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, nothing is drawn.&lt;br /&gt;
&lt;br /&gt;
=== DXDrawWithOffset ===&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme_ASM_API#DXDrawWithOffset|DXDrawWithOffset]] in the API for details.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; works the same way but shifts the drawing relative to the sprite. Supply signed 8-bit offsets in &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$08&lt;br /&gt;
    STA !XOffsetParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$F8&lt;br /&gt;
    STA !YOffsetParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDrawWithOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example shifts the drawing 8 pixels right and 8 pixels up. Positive X moves right and negative X left; positive Y moves down and negative Y up.&lt;br /&gt;
&lt;br /&gt;
The offset changes only where the pose is drawn, not the sprite&#039;s actual position, hitbox, or interactions. It is useful for aligning graphics, adding visual movement, or drawing several parts of an entity from one logical position.&lt;br /&gt;
&lt;br /&gt;
As above, &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; is generated from DrawInfo and stored in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Dynamic Xtreme&#039;s name normalization removes separators such as spaces and underscores and capitalizes each word&#039;s first letter.&lt;br /&gt;
&lt;br /&gt;
=== DrawStatic ===&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme_ASM_API#DrawStatic|DrawStatic]] in the API for details.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme can also draw static poses. Declare them with &amp;lt;code&amp;gt;.IsStatic&amp;lt;/code&amp;gt; in DrawInfo and draw them with &amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt;. Their graphics are already in VRAM, so they do not need &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
When a static pose uses the default tile (0) for all components, drawing takes the tile number from &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, which represents scratch RAM &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;. This lets the same pose, such as a one-tile pose, draw different graphics. Prepare this value before calling &amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    LDA #$80            ; Tile number to draw&lt;br /&gt;
    STA !Tile           ; Scratch RAM $05&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prepare this value for every drawing call that needs it. Setting it only in INIT is insufficient because other routines share the scratch RAM.&lt;br /&gt;
&lt;br /&gt;
For dynamic poses, &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; obtain the tile from the graphics&#039; VRAM cache location, so &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; does not need to be set manually. If a static DrawInfo declares nondefault tiles, drawing uses those values directly.&lt;br /&gt;
&lt;br /&gt;
This example draws a static pose at a normal sprite&#039;s position, without flipping and using palette A:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    REP #$21&lt;br /&gt;
    LDA #!PoseIDMyStaticSprite_Frame0&lt;br /&gt;
    %DrawStatic(0, 1, #$00, #$04, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first parameter selects additional offsets: 0 draws at the supplied position; 1 also applies &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt;. The remaining parameters provide the drawing context, flip, palette, and 16-bit X/Y positions. Quote indexed positions so the comma in &amp;lt;code&amp;gt;,x&amp;lt;/code&amp;gt; is not treated as a macro argument separator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt; ends the routine with &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;, so this example does not add another &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; after the macro.&lt;br /&gt;
&lt;br /&gt;
Here, &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; disables flipping and &amp;lt;code&amp;gt;#$04&amp;lt;/code&amp;gt; selects palette A. These arguments can also use tables or variables when the sprite needs to change orientation or palette.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMyStaticSprite_Frame0&amp;lt;/code&amp;gt; is generated from DrawInfo during installation and appears in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Its name uses PascalCase: remove spaces, underscores, hyphens, and other separators and capitalize each word&#039;s first letter.&lt;br /&gt;
&lt;br /&gt;
For more on declaring static poses, see [[Dynamic_Xtreme_files_and_formats|Dynamic Xtreme files and formats]].&lt;br /&gt;
&lt;br /&gt;
== Install and test the sprite ==&lt;br /&gt;
&lt;br /&gt;
Whenever a resource processed by Dynamic Xtreme changes, reinstall Dynamic Xtreme first and then reinsert the sprites with PIXI. This includes &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;*.bin&amp;lt;/code&amp;gt; graphics, &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; effects, and any other dynamic resource used by the sprite.&lt;br /&gt;
&lt;br /&gt;
Order matters: Dynamic Xtreme must process the resources and regenerate their data and defines before PIXI assembles the sprite with the updated information.&lt;br /&gt;
&lt;br /&gt;
If you add, remove, or modify &amp;lt;code&amp;gt;;#incdyn&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;;#incdri&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;;#incpale&amp;lt;/code&amp;gt; resource includes in the ASM, reinstall Dynamic Xtreme first and then PIXI.&lt;br /&gt;
&lt;br /&gt;
If you only modify the sprite&#039;s &amp;lt;code&amp;gt;*.asm&amp;lt;/code&amp;gt; code without changing those includes, you do not need to reinstall Dynamic Xtreme. Run PIXI again.&lt;br /&gt;
&lt;br /&gt;
For the complete resource installation, configuration, and reinstallation process, see the [[Dynamic_Xtreme_Quick_Start|Dynamic Xtreme Quick Start guide]].&lt;br /&gt;
&lt;br /&gt;
After each installation, test the sprite in-game and check its poses, palettes, flipping, and offsets throughout its states and animations.&lt;br /&gt;
&lt;br /&gt;
== Common mistakes ==&lt;br /&gt;
&lt;br /&gt;
=== Using an unnormalized name in a generated define ===&lt;br /&gt;
&lt;br /&gt;
Names inside Dynamic Xtreme&#039;s generated defines must follow the tool&#039;s normalization: remove spaces, underscores, and hyphens and capitalize each word&#039;s first letter, using PascalCase.&lt;br /&gt;
&lt;br /&gt;
For example, a pose named &amp;lt;code&amp;gt;my_sprite-pose&amp;lt;/code&amp;gt; uses &amp;lt;code&amp;gt;MySpritePose&amp;lt;/code&amp;gt; in a define such as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!DynamicPoseIDMySpritePose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using the original separators, different capitalization, or confusing &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt; prevents Asar from finding the symbol. When unsure, check the exact generated name in &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Incorrectly initializing sprite variables ===&lt;br /&gt;
&lt;br /&gt;
Initialize Dynamic Xtreme&#039;s variables to valid values whenever a sprite is created. With &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt; must start at &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LocalFlip&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt; normally start at 0. Also configure the &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; distances.&lt;br /&gt;
&lt;br /&gt;
Incorrect initialization may reuse a palette, pose, or data left by another sprite in the same slot. Cluster and extended sprites must initialize through the simulated startup routine explained above.&lt;br /&gt;
&lt;br /&gt;
=== Not reserving an Extra Byte for the palette ===&lt;br /&gt;
&lt;br /&gt;
A normal sprite that loads palettes needs at least one Extra Byte in its &amp;lt;code&amp;gt;*.cfg&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;*.json&amp;lt;/code&amp;gt;. Dynamic Xtreme uses &amp;lt;code&amp;gt;Extra Byte 1&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; and commonly uses its low four bits for &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Without any declared Extra Bytes, &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt; will not contain the configuration needed to select the sprite&#039;s palette and version correctly.&lt;br /&gt;
&lt;br /&gt;
=== Not restoring a fixed palette in the short routine ===&lt;br /&gt;
&lt;br /&gt;
A sprite can use a fixed palette already loaded in the level instead of calling &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;. Even then, assign the desired drawing palette manually to &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Values increase by two and select sprite palettes 8–F:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;: palette 8.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;: palette 9.&lt;br /&gt;
* &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt;: palette A.&lt;br /&gt;
* &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt;: palette B.&lt;br /&gt;
* &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt;: palette C.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;: palette D.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt;: palette E.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt;: palette F.&lt;br /&gt;
&lt;br /&gt;
Assign the value in &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; and in the short routine. When &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; selects the short routine, it invalidates &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;, so restore the fixed palette there:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
; Inside INIT&lt;br /&gt;
    LDA #$04            ; Palette A&lt;br /&gt;
    STA !Palette,x&lt;br /&gt;
&lt;br /&gt;
; Inside SpriteCode&lt;br /&gt;
.ShortRoutine&lt;br /&gt;
    LDA #$04            ; Palette A&lt;br /&gt;
    STA !Palette,x&lt;br /&gt;
&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    %SubOffScreen()&lt;br /&gt;
    ; Put your sprite&#039;s logic here&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manual assignment is only for sprites using fixed palettes without &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;. Sprites with dynamic palette loading must retain the assignment flow explained in the palette management section.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_files_and_formats&amp;diff=21394</id>
		<title>Dynamic Xtreme files and formats</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_files_and_formats&amp;diff=21394"/>
		<updated>2026-10-25T21:56:15Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_files_and_formats}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme uses a set of dedicated file formats to give you control over the resources, effects, and data used during gameplay.&lt;br /&gt;
&lt;br /&gt;
This page documents the file types handled by the tool, their purpose, how they work, and their specific formats, including both current and legacy formats. Understanding this structure helps you make full use of Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Many of Dynamic Xtreme&#039;s legacy formats originated in Dynamic X, the earlier version from which the project evolved. They remain fully compatible to support the many existing resources developed for Dynamic X.&lt;br /&gt;
&lt;br /&gt;
The main file types and their formats are described below.&lt;br /&gt;
&lt;br /&gt;
== File types ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme uses several specialized file types:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Dynamic resources:&#039;&#039;&#039; resources stored uncompressed in the ROM. Commonly used for dynamic sprites, graphics changes, tilemap changes, or palette changes.&lt;br /&gt;
* &#039;&#039;&#039;Palette Effects (*.paleffect):&#039;&#039;&#039; files used to register palette effects.&lt;br /&gt;
* &#039;&#039;&#039;Dynamic Info (*.dynamicinfo):&#039;&#039;&#039; files used to insert dynamic resources into the ROM and generate the data required by dynamic sprites.&lt;br /&gt;
* &#039;&#039;&#039;Draw Info (*.drawinfo):&#039;&#039;&#039; files used to generate sprite poses (animation frames) so they can be drawn on screen.&lt;br /&gt;
&lt;br /&gt;
== Including files from PIXI and UberASMTool ==&lt;br /&gt;
&lt;br /&gt;
PIXI and UberASMTool resources can declare the files they use through special comments in their main ASM file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn  &amp;quot;ruta/al/recurso.dynamicinfo&amp;quot;&lt;br /&gt;
;#incdri  &amp;quot;ruta/al/recurso.drawinfo&amp;quot;&lt;br /&gt;
;#incpale &amp;quot;ruta/al/recurso.paleffect&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each directive registers a different file type:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;;#incdyn&amp;lt;/code&amp;gt; includes a &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt; file.&lt;br /&gt;
* &amp;lt;code&amp;gt;;#incdri&amp;lt;/code&amp;gt; includes a &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt; file.&lt;br /&gt;
* &amp;lt;code&amp;gt;;#incpale&amp;lt;/code&amp;gt; includes a &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
Paths are relative to the main ASM containing the directive. Included files can be in the same folder or any of its subfolders.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme searches for these directives only in the main ASM files registered in PIXI&#039;s and UberASMTool&#039;s lists. It does not follow files loaded through &amp;lt;code&amp;gt;incsrc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Resources referenced inside a &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt; or&lt;br /&gt;
&amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; included this way use the&lt;br /&gt;
definition file&#039;s folder as their base directory.&lt;br /&gt;
&lt;br /&gt;
== Dynamic resources ==&lt;br /&gt;
&lt;br /&gt;
Dynamic resources are one of Dynamic Xtreme&#039;s core systems. They are stored uncompressed in the ROM so they can be loaded and used quickly during gameplay.&lt;br /&gt;
&lt;br /&gt;
=== How does the system work? ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme gathers all dynamic resources, organizes them into packages of at most one bank (32 or 64 KB), and automatically inserts them into the ROM. If high banks are available, the tool prioritizes them for insertion to improve space organization.&lt;br /&gt;
&lt;br /&gt;
There is no strict restriction on the type of data that can be inserted, although most files are &#039;&#039;&#039;*.bin&#039;&#039;&#039; files.&lt;br /&gt;
&lt;br /&gt;
=== Common uses ===&lt;br /&gt;
&lt;br /&gt;
Dynamic resources are commonly used for:&lt;br /&gt;
* &#039;&#039;&#039;Graphics:&#039;&#039;&#039; dynamic sprite graphics or real-time graphics replacement.&lt;br /&gt;
* &#039;&#039;&#039;Tilemaps:&#039;&#039;&#039; replacing tiles in the level&#039;s different layers.&lt;br /&gt;
* &#039;&#039;&#039;Palettes:&#039;&#039;&#039; replacing complete palettes or assigning specific palettes to dynamic sprites.&lt;br /&gt;
* &#039;&#039;&#039;Other data:&#039;&#039;&#039; anything you want to store in the ROM, such as .brr audio samples, data tables, and so on.&lt;br /&gt;
&lt;br /&gt;
This makes the system flexible enough for graphics and any other data that needs to be readily available in the ROM.&lt;br /&gt;
&lt;br /&gt;
=== Palette files ===&lt;br /&gt;
&lt;br /&gt;
Currently, the recommended way to save palettes is as binary files (&#039;&#039;&#039;*.bin&#039;&#039;&#039;), with each color taking 2 bytes in the SNES color format. Tools such as [https://www.smwcentral.net/?p=section&amp;amp;a=details&amp;amp;id=24827 Pal2Bin] can help with this.&lt;br /&gt;
&lt;br /&gt;
The SNES uses the BGR555 color format: each color uses 5 bits for blue, 5 for green, and 5 for red.&lt;br /&gt;
&lt;br /&gt;
Conceptually, the bits are arranged as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;-BBBBB GGGGG RRRRR&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
However, because of the SNES byte order, the bytes are stored in reverse order in memory, producing this arrangement:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GGG RRRRR -BBBBB GG&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because this format can be confusing for users unfamiliar with SNES hardware, improved support for &#039;&#039;&#039;*.pal&#039;&#039;&#039; files is planned. This format is more familiar and widely used in modern graphics tools.&lt;br /&gt;
&lt;br /&gt;
Palettes used by dynamic sprites must contain no more than 15 colors. Include only colors 1 through 15 of the corresponding palette, since color 0 is transparent.&lt;br /&gt;
&lt;br /&gt;
=== Dynamic sprite graphics ===&lt;br /&gt;
&lt;br /&gt;
A dynamic sprite&#039;s graphics are divided into poses. Each pose contains the tiles that must be loaded into VRAM to display one animation frame.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme supports two ways to organize these graphics:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;current format&#039;&#039;&#039;, recommended for new resources.&lt;br /&gt;
* The &#039;&#039;&#039;legacy format&#039;&#039;&#039;, retained for compatibility with&lt;br /&gt;
resources made for Dynamic X.&lt;br /&gt;
&lt;br /&gt;
Both formats produce the same result in the game. The only difference is how the graphics must be organized in the file.&lt;br /&gt;
&lt;br /&gt;
==== Current format ====&lt;br /&gt;
&lt;br /&gt;
In the current format, graphics are organized into 16×16-pixel spaces.&lt;br /&gt;
&lt;br /&gt;
Each pose&#039;s tiles are placed consecutively. The next pose&#039;s graphics begin immediately after the previous pose&#039;s.&lt;br /&gt;
&lt;br /&gt;
The author chooses the tile order within each pose in the graphics file. DynamicInfo specifies how many tiles belong to each pose, and DrawInfo specifies where each tile is drawn. Both must match the graphics layout.&lt;br /&gt;
&lt;br /&gt;
For example, a 32×32-pixel pose normally uses four 16×16 tiles:&lt;br /&gt;
&lt;br /&gt;
[[File:imagen 2026-05-17 221817296.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
The number of tiles used by each pose is declared in the&lt;br /&gt;
&amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt; file through&lt;br /&gt;
&amp;lt;code&amp;gt;NumberOf16x16TilesPerPose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme automatically rearranges these graphics into the internal format used for DMA transfers. The resource author therefore does not need to prepare the VRAM layout manually.&lt;br /&gt;
&lt;br /&gt;
This is the recommended format for new resources.&lt;br /&gt;
&lt;br /&gt;
If the final 16×16 tile is only partially used, specify which parts to keep with &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;q3&amp;lt;/code&amp;gt;. Prepare the graphics in a complete 16×16 space; Dynamic Xtreme keeps the indicated parts and discards the rest when processing the resource.&lt;br /&gt;
&lt;br /&gt;
Each cell in the following tables represents an 8×8 tile. The entire table represents the pose&#039;s final 16×16 tile. Green marks used parts and gray marks discarded parts.&lt;br /&gt;
&lt;br /&gt;
===== q =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! !! Left half !! Right half&lt;br /&gt;
|-&lt;br /&gt;
! Top half&lt;br /&gt;
| style=&amp;quot;background-color:#d5f5dc; color:#202122;&amp;quot; | Top-left 8×8 tile: used&lt;br /&gt;
| style=&amp;quot;background-color:#eaecf0; color:#202122;&amp;quot; | Top-right 8×8 tile: unused&lt;br /&gt;
|-&lt;br /&gt;
! Bottom half&lt;br /&gt;
| style=&amp;quot;background-color:#eaecf0; color:#202122;&amp;quot; | Bottom-left 8×8 tile: unused&lt;br /&gt;
| style=&amp;quot;background-color:#eaecf0; color:#202122;&amp;quot; | Bottom-right 8×8 tile: unused&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== h =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! !! Left half !! Right half&lt;br /&gt;
|-&lt;br /&gt;
! Top half&lt;br /&gt;
| style=&amp;quot;background-color:#d5f5dc; color:#202122;&amp;quot; | Top-left 8×8 tile: used&lt;br /&gt;
| style=&amp;quot;background-color:#d5f5dc; color:#202122;&amp;quot; | Top-right 8×8 tile: used&lt;br /&gt;
|-&lt;br /&gt;
! Bottom half&lt;br /&gt;
| style=&amp;quot;background-color:#eaecf0; color:#202122;&amp;quot; | Bottom-left 8×8 tile: unused&lt;br /&gt;
| style=&amp;quot;background-color:#eaecf0; color:#202122;&amp;quot; | Bottom-right 8×8 tile: unused&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== q3 =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! !! Left half !! Right half&lt;br /&gt;
|-&lt;br /&gt;
! Top half&lt;br /&gt;
| style=&amp;quot;background-color:#d5f5dc; color:#202122;&amp;quot; | Top-left 8×8 tile: used&lt;br /&gt;
| style=&amp;quot;background-color:#d5f5dc; color:#202122;&amp;quot; | Top-right 8×8 tile: used&lt;br /&gt;
|-&lt;br /&gt;
! Bottom half&lt;br /&gt;
| style=&amp;quot;background-color:#d5f5dc; color:#202122;&amp;quot; | Bottom-left 8×8 tile: used&lt;br /&gt;
| style=&amp;quot;background-color:#eaecf0; color:#202122;&amp;quot; | Bottom-right 8×8 tile: unused&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Legacy format ====&lt;br /&gt;
&lt;br /&gt;
The legacy format requires the graphics to already be organized into the blocks that DMA will transfer.&lt;br /&gt;
&lt;br /&gt;
For a pose using seven or fewer 16×16 tiles, split each tile into two 16×8 halves. Store all top halves first, followed by all bottom halves.&lt;br /&gt;
&lt;br /&gt;
For example, a pose made of four tiles:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;t1 t2 t3 t4&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
must be stored like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;t1th t2th t3th t4th t1bh t2bh t3bh t4bh&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;th&amp;lt;/code&amp;gt; means the tile&#039;s top half.&lt;br /&gt;
* &amp;lt;code&amp;gt;bh&amp;lt;/code&amp;gt; means the tile&#039;s bottom half.&lt;br /&gt;
&lt;br /&gt;
When a pose contains eight or more 16×16 tiles, each full row of eight tiles can be stored directly. Arrange the remaining tiles using the half-tile system described above.&lt;br /&gt;
&lt;br /&gt;
Each pose&#039;s layout is declared through&lt;br /&gt;
&amp;lt;code&amp;gt;PosesChunksSizes&amp;lt;/code&amp;gt; in the&lt;br /&gt;
&amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This format provides direct control over the internal layout but is harder to prepare and maintain. It is mainly recommended for older resources or advanced use cases.&lt;br /&gt;
&lt;br /&gt;
== Palette effects ==&lt;br /&gt;
&lt;br /&gt;
Palette effect files are stored in the PaletteEffects folder and use the &#039;&#039;&#039;*.paleffect&#039;&#039;&#039; extension.&lt;br /&gt;
&lt;br /&gt;
Palette effects modify the colors used by the game in real time. Dynamic Xtreme&#039;s global palette effect system can use these effects.&lt;br /&gt;
&lt;br /&gt;
The global effect affects every color in each palette enabled to receive it. Likewise, an effect applied to a whole sprite affects its entire palette. These systems do not select individual colors within a palette.&lt;br /&gt;
&lt;br /&gt;
To apply an effect only to specific colors, do it manually using the macros and routines described in the [[Dynamic_Xtreme_ASM_API|Dynamic Xtreme ASM API]].&lt;br /&gt;
&lt;br /&gt;
Internally, these systems modify the palette colors&#039; &#039;&#039;&#039;RGB&#039;&#039;&#039; or &#039;&#039;&#039;HSL&#039;&#039;&#039; channels to produce different visual effects.&lt;br /&gt;
&lt;br /&gt;
Common uses include:&lt;br /&gt;
&lt;br /&gt;
* Day-to-night transitions.&lt;br /&gt;
* Red flashes to signal danger.&lt;br /&gt;
* Blinking cyan effects for objects about to explode.&lt;br /&gt;
* Shifting tints for disco-style effects.&lt;br /&gt;
* Smooth transitions between visual states.&lt;br /&gt;
* Lighting or atmosphere effects.&lt;br /&gt;
&lt;br /&gt;
The system supports many combinations and effects.&lt;br /&gt;
&lt;br /&gt;
=== Effect types ===&lt;br /&gt;
&lt;br /&gt;
The following effects are available:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixRGB (ID 0)&#039;&#039;&#039;: interpolates the &#039;&#039;&#039;RGB&#039;&#039;&#039; channels toward a base color.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixHSL (ID 1)&#039;&#039;&#039;: interpolates the &#039;&#039;&#039;HSL&#039;&#039;&#039; channels toward a base color.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixRG (ID 2)&#039;&#039;&#039;: interpolates only &#039;&#039;&#039;R&#039;&#039;&#039; and &#039;&#039;&#039;G&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixHS (ID 3)&#039;&#039;&#039;: interpolates only &#039;&#039;&#039;H&#039;&#039;&#039; and &#039;&#039;&#039;S&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixRB (ID 4)&#039;&#039;&#039;: interpolates only &#039;&#039;&#039;R&#039;&#039;&#039; and &#039;&#039;&#039;B&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixHL (ID 5)&#039;&#039;&#039;: interpolates only &#039;&#039;&#039;H&#039;&#039;&#039; and &#039;&#039;&#039;L&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixGB (ID 6)&#039;&#039;&#039;: interpolates only &#039;&#039;&#039;G&#039;&#039;&#039; and &#039;&#039;&#039;B&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixSL (ID 7)&#039;&#039;&#039;: interpolates only &#039;&#039;&#039;S&#039;&#039;&#039; and &#039;&#039;&#039;L&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixR (ID 8)&#039;&#039;&#039;: interpolates only the &#039;&#039;&#039;R&#039;&#039;&#039; channel.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixH (ID 9)&#039;&#039;&#039;: interpolates only the &#039;&#039;&#039;H&#039;&#039;&#039; channel.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixG (ID 10)&#039;&#039;&#039;: interpolates only the &#039;&#039;&#039;G&#039;&#039;&#039; channel.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixS (ID 11)&#039;&#039;&#039;: interpolates only the &#039;&#039;&#039;S&#039;&#039;&#039; channel.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixB (ID 12)&#039;&#039;&#039;: interpolates only the &#039;&#039;&#039;B&#039;&#039;&#039; channel.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixL (ID 13)&#039;&#039;&#039;: interpolates only the &#039;&#039;&#039;L&#039;&#039;&#039; channel.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;PalTransitionRGB (ID 14)&#039;&#039;&#039;: interpolates an entire palette toward another using &#039;&#039;&#039;RGB&#039;&#039;&#039; channels.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;PalTransitionHSL (ID 15)&#039;&#039;&#039;: interpolates an entire palette toward another using &#039;&#039;&#039;HSL&#039;&#039;&#039; channels.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;PalFunctionRGB (ID 16)&#039;&#039;&#039;: applies a linear transformation to the &#039;&#039;&#039;RGB&#039;&#039;&#039; channels:&lt;br /&gt;
&lt;br /&gt;
* R = R11*R + R12*G + R13*B&lt;br /&gt;
* G = R21*R + R22*G + R23*B&lt;br /&gt;
* B = R31*R + R32*G + R33*B&lt;br /&gt;
&lt;br /&gt;
Where:&lt;br /&gt;
&lt;br /&gt;
* RXY are ratios.&lt;br /&gt;
* R is the red channel.&lt;br /&gt;
* G is the green channel.&lt;br /&gt;
* B is the blue channel.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; this effect is not implemented yet.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;PalFunctionHSL (ID 17)&#039;&#039;&#039;: applies a linear transformation to the &#039;&#039;&#039;HSL&#039;&#039;&#039; channels:&lt;br /&gt;
&lt;br /&gt;
* H = R11*H + R12*S + R13*L&lt;br /&gt;
* S = R21*H + R22*S + R23*L&lt;br /&gt;
* L = R31*H + R32*S + R33*L&lt;br /&gt;
&lt;br /&gt;
Where:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RXY&#039;&#039;&#039; are ratios.&lt;br /&gt;
* &#039;&#039;&#039;H&#039;&#039;&#039; is hue.&lt;br /&gt;
* &#039;&#039;&#039;S&#039;&#039;&#039; is saturation.&lt;br /&gt;
* &#039;&#039;&#039;L&#039;&#039;&#039; is lightness.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; this effect is not implemented yet.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== File format ====&lt;br /&gt;
&lt;br /&gt;
Palette effects use a JSON-based format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: []&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Effects&#039;&#039;&#039;: the list of effects used.&lt;br /&gt;
&lt;br /&gt;
===== Simple format =====&lt;br /&gt;
&lt;br /&gt;
The simple format defines a single effect:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Channel1&amp;quot;: 31,&lt;br /&gt;
  &amp;quot;Channel2&amp;quot;: 0,&lt;br /&gt;
  &amp;quot;Channel3&amp;quot;: 0,&lt;br /&gt;
  &amp;quot;Ratio1&amp;quot;: 64,&lt;br /&gt;
  &amp;quot;Ratio2&amp;quot;: 64,&lt;br /&gt;
  &amp;quot;Ratio3&amp;quot;: 64,&lt;br /&gt;
  &amp;quot;EffectType&amp;quot;: 0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;Channel1&#039;&#039;&#039;, &#039;&#039;&#039;Channel2&#039;&#039;&#039;, and &#039;&#039;&#039;Channel3&#039;&#039;&#039; contain the main channel values&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For &#039;&#039;&#039;RGB&#039;&#039;&#039; effects:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;1 = R&amp;lt;/li&amp;gt;   &amp;lt;li&amp;gt;2 = G&amp;lt;/li&amp;gt;   &amp;lt;li&amp;gt;3 = B&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For &#039;&#039;&#039;HSL&#039;&#039;&#039; effects:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;1 = H&amp;lt;/li&amp;gt;   &amp;lt;li&amp;gt;2 = S&amp;lt;/li&amp;gt;   &amp;lt;li&amp;gt;3 = L&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;Ratio1&#039;&#039;&#039;, &#039;&#039;&#039;Ratio2&#039;&#039;&#039;, and &#039;&#039;&#039;Ratio3&#039;&#039;&#039; are interpolation factors used to calculate how strongly the effect influences each channel. Values range from 0 (minimum influence) to 127 (maximum influence).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;EffectType&#039;&#039;&#039; is the ID of the effect used.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, the &amp;lt;code&amp;gt;MixRGB&amp;lt;/code&amp;gt; above blends the original colors toward red: &amp;lt;code&amp;gt;Channel1 = 31&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Channel2 = 0&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Channel3 = 0&amp;lt;/code&amp;gt;. With all three ratios set to 64, the result is approximately halfway between each original color and that red. A black color therefore becomes a medium-intensity red. Increasing the ratios brings the result closer to the specified red.&lt;br /&gt;
&lt;br /&gt;
===== Palette transitions =====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt; effects interpolate colors from one&lt;br /&gt;
palette toward another.&lt;br /&gt;
&lt;br /&gt;
Unlike regular blending effects, these use the &amp;lt;code&amp;gt;Palette&amp;lt;/code&amp;gt; field to specify the target palette:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Palette&amp;quot;: &amp;quot;Palettes/NightPalette.bin&amp;quot;,&lt;br /&gt;
  &amp;quot;Ratio1&amp;quot;: 64,&lt;br /&gt;
  &amp;quot;Ratio2&amp;quot;: 64,&lt;br /&gt;
  &amp;quot;Ratio3&amp;quot;: 64,&lt;br /&gt;
  &amp;quot;EffectType&amp;quot;: 14&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example uses &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;, whose ID is&lt;br /&gt;
&amp;lt;code&amp;gt;14&amp;lt;/code&amp;gt;. For an HSL transition, use&lt;br /&gt;
&amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt;, whose ID is &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The file specified in &amp;lt;code&amp;gt;Palette&amp;lt;/code&amp;gt; must contain 2-byte BGR555 colors. Dynamic Xtreme automatically converts the palette into the internal format required by the RGB or HSL effect.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt;, and&lt;br /&gt;
&amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; control interpolation for their respective&lt;br /&gt;
channels and must range from 0 to 127.&lt;br /&gt;
&lt;br /&gt;
When the &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; is in the traditional &amp;lt;code&amp;gt;PaletteEffects&amp;lt;/code&amp;gt; folder, the&lt;br /&gt;
&amp;lt;code&amp;gt;Palette&amp;lt;/code&amp;gt; path is resolved relative to&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicResources&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
When the effect is included from PIXI or UberASMTool through&lt;br /&gt;
&amp;lt;code&amp;gt;;#incpale&amp;lt;/code&amp;gt;, its path is resolved relative to the folder&lt;br /&gt;
containing the &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
==== Value ranges ====&lt;br /&gt;
&lt;br /&gt;
* Channel values (&#039;&#039;&#039;Channel&#039;&#039;&#039;) range from &#039;&#039;&#039;0&#039;&#039;&#039; to &#039;&#039;&#039;31&#039;&#039;&#039;.&lt;br /&gt;
* Ratio values (&#039;&#039;&#039;Ratio&#039;&#039;&#039;) range from &#039;&#039;&#039;0&#039;&#039;&#039; to &#039;&#039;&#039;127&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== DynamicInfo ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DynamicInfo&#039;&#039;&#039; files are stored in the &#039;&#039;&#039;DynamicInfos&#039;&#039;&#039; folder and use the &#039;&#039;&#039;*.dynamicinfo&#039;&#039;&#039; extension.&lt;br /&gt;
&lt;br /&gt;
These files have two main purposes:&lt;br /&gt;
&lt;br /&gt;
* Insert dynamic resources into the ROM.&lt;br /&gt;
* Specify which graphics belong to dynamic sprites and how each pose must be loaded.&lt;br /&gt;
&lt;br /&gt;
The basic structure of a DynamicInfo file is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PosesGraphics:&lt;br /&gt;
    MyGraphics.bin&lt;br /&gt;
    AnotherGraphics.bin&lt;br /&gt;
&lt;br /&gt;
Palettes:&lt;br /&gt;
    MyPal.bin&lt;br /&gt;
    AnotherPal.bin&lt;br /&gt;
&lt;br /&gt;
Resources:&lt;br /&gt;
    MyResource.bin&lt;br /&gt;
    AnotherResource.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These sections are lists of dynamic resources to be included by Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
The base directory for paths depends on how the DynamicInfo file is registered:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Base directory for PosesGraphics, Palettes, and Resources files&lt;br /&gt;
|-&lt;br /&gt;
| Traditional folders: DynamicInfo inside &amp;lt;code&amp;gt;DynamicInfos&amp;lt;/code&amp;gt;&lt;br /&gt;
| Paths are relative to &amp;lt;code&amp;gt;DynamicResources&amp;lt;/code&amp;gt;, next to the Dynamic Xtreme executable.&lt;br /&gt;
|-&lt;br /&gt;
| Included through &amp;lt;code&amp;gt;;#incdyn&amp;lt;/code&amp;gt;&lt;br /&gt;
| Paths are relative to the folder containing the included &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt; file.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For example, with the traditional method, &amp;lt;code&amp;gt;Graficos/MyGraphics.bin&amp;lt;/code&amp;gt; is found at &amp;lt;code&amp;gt;DynamicResources/Graficos/MyGraphics.bin&amp;lt;/code&amp;gt;, not beside the DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PosesGraphics&#039;&#039;&#039; contains dynamic sprite graphics files. These must use the &#039;&#039;&#039;*.bin&#039;&#039;&#039; format.&lt;br /&gt;
* &#039;&#039;&#039;Palettes&#039;&#039;&#039; contains palette files. These currently use the &#039;&#039;&#039;*.bin&#039;&#039;&#039; format, with &#039;&#039;&#039;*.pal&#039;&#039;&#039; support planned for the future.&lt;br /&gt;
* &#039;&#039;&#039;Resources&#039;&#039;&#039; includes arbitrary dynamic resources without a specific format restriction.&lt;br /&gt;
&lt;br /&gt;
When multiple files are listed under PosesGraphics, they are combined internally into one large graphics block in declaration order.&lt;br /&gt;
&lt;br /&gt;
Each pose is then cut from that combined data and stored in the ROM in the arrangement best suited to the dynamic system.&lt;br /&gt;
&lt;br /&gt;
As a result, there is no significant practical difference between:&lt;br /&gt;
&lt;br /&gt;
* Using one large graphics file.&lt;br /&gt;
* Using several separate smaller files.&lt;br /&gt;
&lt;br /&gt;
Both approaches produce the same internal result in Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
In addition to these resource lists, &#039;&#039;&#039;DynamicInfo&#039;&#039;&#039; files define the dynamic poses used by the sprite.&lt;br /&gt;
&lt;br /&gt;
How those poses are defined depends on the resource&#039;s format:&lt;br /&gt;
&lt;br /&gt;
* Current format (&#039;&#039;&#039;NumberOf16x16TilesPerPose&#039;&#039;&#039;).&lt;br /&gt;
* Legacy format (&#039;&#039;&#039;PosesChunksSizes&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
=== Current format ===&lt;br /&gt;
&lt;br /&gt;
The current format was designed to simplify creating and maintaining dynamic sprites.&lt;br /&gt;
&lt;br /&gt;
You only need to specify how many 16×16 tiles each pose uses. Dynamic Xtreme processes the graphics and converts them to the optimized format used internally by the dynamic system.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
NumberOf16x16TilesPerPose:&lt;br /&gt;
.Pose0 5&lt;br /&gt;
.Pose1 7h&lt;br /&gt;
.Pose2..6 4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example:&lt;br /&gt;
&lt;br /&gt;
* Pose0 uses five 16×16 tiles.&lt;br /&gt;
* Pose1 uses seven 16×16 tiles plus a top half (16×8).&lt;br /&gt;
* Pose2 through Pose6 use four 16×16 tiles each.&lt;br /&gt;
&lt;br /&gt;
Modifiers can represent partial tiles:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;q&#039;&#039;&#039;: top-left 8×8 tile.&lt;br /&gt;
* &#039;&#039;&#039;h&#039;&#039;&#039;: top half (16×8).&lt;br /&gt;
* &#039;&#039;&#039;q3&#039;&#039;&#039;: top half plus bottom-left tile (16×8 + 8×8).&lt;br /&gt;
&lt;br /&gt;
This allows a 16×16 tile to contain only part of its graphics. Partial tiles do not support every possible combination, because many would be impractical for the system. Only the most common, useful arrangements are supported.&lt;br /&gt;
&lt;br /&gt;
Internally, Dynamic Xtreme automatically converts this format to the legacy format, which is optimized for more efficient DMA transfers to VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Legacy format ===&lt;br /&gt;
&lt;br /&gt;
The legacy format uses a table named PosesChunksSizes to specify the internal dynamic graphics layout manually.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PosesChunksSizes:&lt;br /&gt;
Pose0_PoseChunksSizes:&lt;br /&gt;
    db $02,$02&lt;br /&gt;
Pose1_PoseChunksSizes:&lt;br /&gt;
    db $02,$02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each pose has a subtable containing two values.&lt;br /&gt;
&lt;br /&gt;
These values represent how many DMA operations would be needed to transfer the pose&#039;s graphics into VRAM under ideal conditions: assuming the sprite is aligned to the start of the sprite VRAM area. Under those conditions, one or two DMA operations are needed.&lt;br /&gt;
&lt;br /&gt;
Usually, the first DMA operation transfers more data than the second.&lt;br /&gt;
&lt;br /&gt;
Each value specifies the number of 8×8 tiles transferred by that DMA operation.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
db $02,$02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
means:&lt;br /&gt;
&lt;br /&gt;
* The first DMA operation transfers two 8×8 tiles.&lt;br /&gt;
* The second transfers another two 8×8 tiles.&lt;br /&gt;
&lt;br /&gt;
In special cases where the sprite uses enough 16×16 tiles to fill exact VRAM rows, such as multiples of eight 16×16 tiles, the entire transfer can use a single DMA operation. In those cases, set the second value to $00.&lt;br /&gt;
&lt;br /&gt;
The current format replaced this format because most users found it complex and unintuitive. NumberOf16x16TilesPerPose is now recommended, although the legacy format remains fully compatible and offers more flexibility for advanced cases.&lt;br /&gt;
&lt;br /&gt;
== DrawInfo ==&lt;br /&gt;
&lt;br /&gt;
DrawInfo files are stored in DrawInfos with the &#039;&#039;&#039;*.drawinfo&#039;&#039;&#039; extension. They contain the information needed to draw poses on screen.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme collects this information and automatically generates optimized graphics routines. Each routine groups poses with similar characteristics and is optimized specifically for that kind of pose. This provides a shared pose drawing system that is efficient in a wide range of situations.&lt;br /&gt;
&lt;br /&gt;
Understanding DrawInfo files requires a basic understanding of SNES OAM.&lt;br /&gt;
&lt;br /&gt;
OAM is memory used to store sprite information. SMW uses 8×8 and 16×16 tiles.&lt;br /&gt;
&lt;br /&gt;
Each tile has the following attributes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;TileCode&#039;&#039;&#039;: sometimes simply called Tile, this is the internal ID the console uses to select a particular graphic in VRAM.&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; for dynamic sprites, define TileCodes as if the sprite were loaded at the start of the sprite VRAM area.&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
Dynamic Xtreme automatically adjusts these values based on where the pose is actually loaded in VRAM during gameplay.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;Properties&#039;&#039;&#039;: a byte containing the tile&#039;s properties, using this format:&lt;br /&gt;
* &#039;&#039;&#039;YXCCPPPT&#039;&#039;&#039;&lt;br /&gt;
Where:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;Y&#039;&#039;&#039;: whether the tile is vertically flipped.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;X&#039;&#039;&#039;: whether the tile is horizontally flipped.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;CC&#039;&#039;&#039;: tile priority relative to layers (higher value = higher priority).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;PPP&#039;&#039;&#039;: sprite palette (000 =&amp;gt; palette 8, 001 =&amp;gt; palette 9, ..., 111 =&amp;gt; palette F).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;T&#039;&#039;&#039;: graphics page (0 =&amp;gt; SP12, 1 =&amp;gt; SP34).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; common Properties can be set for all tiles in a pose or sprite. The most important DrawInfo properties are therefore usually Y, X, and T, while CC and PPP are commonly set by the calling code.&lt;br /&gt;
&lt;br /&gt;
For dynamic sprites, T normally does not need to be set manually: Dynamic Xtreme detects the pose&#039;s graphics page and sets this bit automatically.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;Size&#039;&#039;&#039;: tile size:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;$00: small tile (8×8).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;$02: large tile (16×16).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each tile also has:&lt;br /&gt;
&lt;br /&gt;
* X displacement (X Offset)&lt;br /&gt;
* Y displacement (Y Offset)&lt;br /&gt;
&lt;br /&gt;
These values move the tile relative to the sprite&#039;s base position.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme supports two DrawInfo formats: current and legacy.&lt;br /&gt;
&lt;br /&gt;
=== Current format ===&lt;br /&gt;
&lt;br /&gt;
The current DrawInfo format was designed to make drawing files much easier to read and maintain.&lt;br /&gt;
&lt;br /&gt;
Unlike the legacy format, it supports:&lt;br /&gt;
&lt;br /&gt;
* Grouping multiple poses.&lt;br /&gt;
* Grouping tile ranges.&lt;br /&gt;
* Using individual default values.&lt;br /&gt;
* Omitting unnecessary subtables.&lt;br /&gt;
* Defining individual values or complete value lists.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MyPose_Pose0..4:&lt;br /&gt;
.NumberOfTiles: 5&lt;br /&gt;
.TileCode2: $02&lt;br /&gt;
.TileCode3..4: $04&lt;br /&gt;
.Properties: $00,$40,$00,$00,$40&lt;br /&gt;
.XOffsets: $00,$10,$F8,$08,$18&lt;br /&gt;
.XPivot: $08&lt;br /&gt;
.YOffset2..4: $10&lt;br /&gt;
.YPivot: $10&lt;br /&gt;
.Size0..4: $02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;MyPose_Pose0..4&#039;&#039;&#039;: shared information for poses 0 through 4 with the name &amp;quot;MyPose&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;.NumberOfTiles&#039;&#039;&#039;: each pose uses five tiles.&lt;br /&gt;
* &#039;&#039;&#039;.TileCode2&#039;&#039;&#039;: changes only tile 2&#039;s &#039;&#039;&#039;TileCode&#039;&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;.TileCode3..4&#039;&#039;&#039;: changes the &#039;&#039;&#039;TileCode&#039;&#039;&#039; for tiles 3 and 4.&lt;br /&gt;
* &#039;&#039;&#039;.Properties&#039;&#039;&#039;: an individual &#039;&#039;&#039;Properties&#039;&#039;&#039; value for every tile.&lt;br /&gt;
* &#039;&#039;&#039;.XOffsets&#039;&#039;&#039;: an individual &#039;&#039;&#039;XOffset&#039;&#039;&#039; for every tile.&lt;br /&gt;
* &#039;&#039;&#039;.YOffset2..4&#039;&#039;&#039;: changes &#039;&#039;&#039;YOffset&#039;&#039;&#039; only for tiles 2 through 4.&lt;br /&gt;
* &#039;&#039;&#039;.Size0..4&#039;&#039;&#039;: sets the size of tiles 0 through 4.&lt;br /&gt;
&lt;br /&gt;
Tiles are numbered from 0. For example, &amp;lt;code&amp;gt;.NumberOfTiles: 5&amp;lt;/code&amp;gt; provides tiles 0 through 4.&lt;br /&gt;
&lt;br /&gt;
Singular directives change one tile or a specified range of tiles.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.TileCode2: $02&lt;br /&gt;
.TileCode3..4: $04&lt;br /&gt;
.YOffset1..3: $10&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In these cases:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;.TileCode2:&#039;&#039;&#039;: changes only tile 2.&lt;br /&gt;
* &#039;&#039;&#039;.TileCode3..4&#039;&#039;&#039;: changes only tiles 3 and 4.&lt;br /&gt;
* &#039;&#039;&#039;.YOffset1..3&#039;&#039;&#039;: changes YOffset for tiles 1 through 3.&lt;br /&gt;
&lt;br /&gt;
Plural directives explicitly define a complete value list for every tile in the pose.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.Properties: $00,$40,$00,$00,$40&lt;br /&gt;
.XOffsets: $00,$10,$F8,$08,$18&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In these cases:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;.Properties&#039;&#039;&#039;: a complete Properties list.&lt;br /&gt;
* &#039;&#039;&#039;.XOffsets&#039;&#039;&#039;: a complete XOffsets list.&lt;br /&gt;
&lt;br /&gt;
This allows simple general settings to be combined with specific changes only where needed.&lt;br /&gt;
&lt;br /&gt;
Declarations are applied in the order they appear. If several change the same tile attribute, the last value wins. For example, after &amp;lt;code&amp;gt;.Properties: $00,$40,$00,$00,$40&amp;lt;/code&amp;gt;, write &amp;lt;code&amp;gt;.Property2: $80&amp;lt;/code&amp;gt; to change only tile 2&#039;s property to &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;. If you write the complete list afterward, that list replaces the previous values for all tiles.&lt;br /&gt;
&lt;br /&gt;
When a value is not explicitly defined, Dynamic Xtreme uses these defaults:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;TileCode&#039;&#039;&#039;:  $00&lt;br /&gt;
* &#039;&#039;&#039;Property&#039;&#039;&#039;:  $00&lt;br /&gt;
* &#039;&#039;&#039;XOffset&#039;&#039;&#039;:   $00&lt;br /&gt;
* &#039;&#039;&#039;YOffset&#039;&#039;&#039;:   $00&lt;br /&gt;
* &#039;&#039;&#039;Size&#039;&#039;&#039;:      $02&lt;br /&gt;
&lt;br /&gt;
Unlike the legacy format, these defaults work individually per tile, letting you omit only the unnecessary information without affecting the rest of the pose.&lt;br /&gt;
&lt;br /&gt;
Offsets specify each tile&#039;s position relative to the sprite, in pixels. Without flipping, &amp;lt;code&amp;gt;XOffset&amp;lt;/code&amp;gt; is added to the sprite&#039;s X position and &amp;lt;code&amp;gt;YOffset&amp;lt;/code&amp;gt; to its Y position. For example, an &amp;lt;code&amp;gt;XOffset&amp;lt;/code&amp;gt; of &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; puts the tile 16 pixels to the right; &amp;lt;code&amp;gt;$F8&amp;lt;/code&amp;gt; represents −8 and puts it 8 pixels to the left.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XPivot&#039;&#039;&#039; and &#039;&#039;&#039;YPivot&#039;&#039;&#039; calculate where tiles should be placed when the whole pose is flipped horizontally or vertically. They reflect the layout rather than rotating the pose.&lt;br /&gt;
&lt;br /&gt;
For horizontal flipping, the calculation follows these steps:&lt;br /&gt;
&lt;br /&gt;
# Start with the sprite&#039;s X position.&lt;br /&gt;
# Add &amp;lt;code&amp;gt;XPivot&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Subtract the tile&#039;s original &amp;lt;code&amp;gt;XOffset&amp;lt;/code&amp;gt; to reverse its displacement.&lt;br /&gt;
# For a 16×16 tile, subtract another 8 pixels to adjust for its size. An 8×8 tile needs no such adjustment.&lt;br /&gt;
&lt;br /&gt;
The flipped tile&#039;s X position is therefore:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;8×8 tile:&#039;&#039;&#039; &amp;lt;code&amp;gt;sprite X + XPivot − XOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;16×16 tile:&#039;&#039;&#039; &amp;lt;code&amp;gt;sprite X + XPivot − XOffset − 8&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For example, a pose has two 16×16 tiles with &amp;lt;code&amp;gt;XOffset&amp;lt;/code&amp;gt; values of 0 and 16. Setting &amp;lt;code&amp;gt;.XPivot: $18&amp;lt;/code&amp;gt; (24 decimal) swaps their positions when the pose is flipped:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tile !! Unflipped !! Horizontally flipped&lt;br /&gt;
|-&lt;br /&gt;
| First: XOffset = 0&lt;br /&gt;
| Sprite X + 0&lt;br /&gt;
| Sprite X + 24 − 0 − 8 = Sprite X + 16&lt;br /&gt;
|-&lt;br /&gt;
| Second: XOffset = 16&lt;br /&gt;
| Sprite X + 16&lt;br /&gt;
| Sprite X + 24 − 16 − 8 = Sprite X + 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Vertical flipping uses the same calculation with the sprite&#039;s Y position, &amp;lt;code&amp;gt;YPivot&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;YOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
These flipped offsets are calculated during installation. During gameplay, the drawing routine uses the offsets for the requested flip.&lt;br /&gt;
&lt;br /&gt;
If &#039;&#039;&#039;XPivot&#039;&#039;&#039; is omitted, the pose does not support horizontal flipping. Likewise, omitting &#039;&#039;&#039;YPivot&#039;&#039;&#039; disables vertical flipping for that pose.&lt;br /&gt;
&lt;br /&gt;
This lets Dynamic Xtreme generate more optimized graphics routines when those features are unnecessary, while slightly reducing ROM usage.&lt;br /&gt;
&lt;br /&gt;
You can also use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.IsStatic&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This marks the defined poses as static rather than dynamic. All poses are dynamic by default.&lt;br /&gt;
&lt;br /&gt;
The legacy DrawInfo format remains fully compatible. The current format primarily makes DrawInfo files easier to write, read, and maintain while retaining flexibility.&lt;br /&gt;
&lt;br /&gt;
=== Legacy format ===&lt;br /&gt;
&lt;br /&gt;
Legacy DrawInfo uses separate tables to define each pose tile attribute.&lt;br /&gt;
&lt;br /&gt;
This format follows the structure commonly used in hand-written SNES graphics routines. It was intended to give sprite authors familiar with that approach a recognizable, intuitive layout for DrawInfo.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dynamic: &lt;br /&gt;
true&lt;br /&gt;
&lt;br /&gt;
Tiles:&lt;br /&gt;
MyPose0_Tiles:&lt;br /&gt;
    db $00&lt;br /&gt;
MyPose1_Tiles:&lt;br /&gt;
    db $00&lt;br /&gt;
&lt;br /&gt;
Properties:&lt;br /&gt;
MyPose0_Properties:&lt;br /&gt;
    db $00&lt;br /&gt;
MyPose1_Properties:&lt;br /&gt;
    db $00&lt;br /&gt;
&lt;br /&gt;
XDisplacements:&lt;br /&gt;
MyPose0_XDisp:&lt;br /&gt;
    db $00&lt;br /&gt;
MyPose1_XDisp:&lt;br /&gt;
    db $00&lt;br /&gt;
MyPose0_XDispFlip:&lt;br /&gt;
    db $00&lt;br /&gt;
MyPose1_XDispFlip:&lt;br /&gt;
    db $00&lt;br /&gt;
&lt;br /&gt;
YDisplacements:&lt;br /&gt;
MyPose0_YDisp:&lt;br /&gt;
    db $01&lt;br /&gt;
MyPose1_YDisp:&lt;br /&gt;
    db $01&lt;br /&gt;
MyPose0_YDispFlip:&lt;br /&gt;
    db $FF&lt;br /&gt;
MyPose1_YDispFlip:&lt;br /&gt;
    db $FF&lt;br /&gt;
&lt;br /&gt;
Sizes:&lt;br /&gt;
MyPose0_Sizes:&lt;br /&gt;
    db $02&lt;br /&gt;
MyPose1_Sizes:&lt;br /&gt;
    db $02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this format:&lt;br /&gt;
&lt;br /&gt;
* Each attribute has its own section.&lt;br /&gt;
* Each pose requires a separate subtable.&lt;br /&gt;
* Every value must be written manually.&lt;br /&gt;
* There are no tile ranges or pose groups.&lt;br /&gt;
&lt;br /&gt;
The main tables are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tiles&#039;&#039;&#039;: TileCodes.&lt;br /&gt;
* &#039;&#039;&#039;Properties&#039;&#039;&#039;: OAM properties.&lt;br /&gt;
* &#039;&#039;&#039;XDisplacements&#039;&#039;&#039;: horizontal offsets.&lt;br /&gt;
* &#039;&#039;&#039;YDisplacements&#039;&#039;&#039;: vertical offsets.&lt;br /&gt;
* &#039;&#039;&#039;Sizes&#039;&#039;&#039;: tile sizes (8×8 or 16×16).&lt;br /&gt;
&lt;br /&gt;
XDisplacements and YDisplacements can also have flipped versions:&lt;br /&gt;
&lt;br /&gt;
* XDispFlip&lt;br /&gt;
* YDispFlip&lt;br /&gt;
&lt;br /&gt;
These tables let you specify the offsets used for horizontal or vertical flipping manually.&lt;br /&gt;
&lt;br /&gt;
The directive:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dynamic: true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
marks the poses as dynamic. Set it to false to mark them as static.&lt;br /&gt;
&lt;br /&gt;
As in the current format, default values are automatic. When a table is absent, Dynamic Xtreme uses:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;TileCode&#039;&#039;&#039;:  $00&lt;br /&gt;
* &#039;&#039;&#039;Property&#039;&#039;&#039;:  $00&lt;br /&gt;
* &#039;&#039;&#039;XOffset&#039;&#039;&#039;:   $00&lt;br /&gt;
* &#039;&#039;&#039;YOffset&#039;&#039;&#039;:   $00&lt;br /&gt;
* &#039;&#039;&#039;Size&#039;&#039;&#039;:      $02&lt;br /&gt;
&lt;br /&gt;
This format remains fully compatible with Dynamic Xtreme, although the current format is recommended because it is considerably easier to read, maintain, and edit.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_Quick_Start&amp;diff=21393</id>
		<title>Dynamic Xtreme Quick Start</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=Dynamic_Xtreme_Quick_Start&amp;diff=21393"/>
		<updated>2026-10-25T21:55:41Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_Quick_Start}}&lt;br /&gt;
&lt;br /&gt;
This guide explains how to perform a basic Dynamic Xtreme installation on Windows or Linux.&lt;br /&gt;
&lt;br /&gt;
If this is your first time using the tool, follow the steps in order. You do not need to understand the system&#039;s internals to install it.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme requires the .NET 8 runtime. Download and install the version for your operating system from Microsoft&#039;s official website:&lt;br /&gt;
&lt;br /&gt;
[https://dotnet.microsoft.com/download/dotnet/8.0 .NET 8 Runtime]&lt;br /&gt;
&lt;br /&gt;
The tool supports Windows and Linux. You only need the .NET runtime, not the full SDK.&lt;br /&gt;
&lt;br /&gt;
You can download Dynamic Xtreme from SNEStorage: [https://snestorage.dev/Resource/7 SNEStorage - Dynamic Xtreme]&lt;br /&gt;
&lt;br /&gt;
== Prepare your resources ==&lt;br /&gt;
&lt;br /&gt;
Before running Dynamic Xtreme, add all the resources you want to install to your project.&lt;br /&gt;
&lt;br /&gt;
=== Resources for PIXI and UberASMTool ===&lt;br /&gt;
&lt;br /&gt;
Current resources usually include their&lt;br /&gt;
&amp;lt;code&amp;gt;*.asm&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;*.json&amp;lt;/code&amp;gt; file along with the files they&lt;br /&gt;
need. Copy the entire package without changing its folder structure.&lt;br /&gt;
&lt;br /&gt;
In PIXI, use the folder for the sprite type:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprites&amp;lt;/code&amp;gt; for normal sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;cluster&amp;lt;/code&amp;gt; for cluster sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;extended&amp;lt;/code&amp;gt; for extended sprites.&lt;br /&gt;
* For other types, use the folder specified by the resource.&lt;br /&gt;
&lt;br /&gt;
In UberASMTool, use the folder for the code type:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;level&amp;lt;/code&amp;gt; for level code.&lt;br /&gt;
* &amp;lt;code&amp;gt;overworld&amp;lt;/code&amp;gt; for overworld code.&lt;br /&gt;
* &amp;lt;code&amp;gt;gamemode&amp;lt;/code&amp;gt; for game mode code.&lt;br /&gt;
* For other types, use the folder specified by the resource.&lt;br /&gt;
&lt;br /&gt;
After copying the resource, add it to PIXI&#039;s or UberASMTool&#039;s list file as usual.&lt;br /&gt;
&lt;br /&gt;
Resources prepared for Dynamic Xtreme already contain the necessary declarations in their main ASM file. Keep the ASM, JSON, and supplied folders together to preserve their relative paths.&lt;br /&gt;
&lt;br /&gt;
=== Traditional folders ===&lt;br /&gt;
&lt;br /&gt;
Some resources use Dynamic Xtreme&#039;s traditional folders. In that case, use this arrangement:&lt;br /&gt;
&lt;br /&gt;
These folders are next to the Dynamic Xtreme executable: &amp;lt;code&amp;gt;dxt.exe&amp;lt;/code&amp;gt; on Windows or &amp;lt;code&amp;gt;dxt&amp;lt;/code&amp;gt; on Linux.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File type&lt;br /&gt;
! Folder&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;DynamicInfos&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;DrawInfos&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteEffects&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Graphics, palettes, and other related files&lt;br /&gt;
| &amp;lt;code&amp;gt;DynamicResources&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Always use the method specified by the resource. Do not move a modern sprite&#039;s or UberASM resource&#039;s files into the traditional folders unless its instructions tell you to.&lt;br /&gt;
&lt;br /&gt;
== Full installation ==&lt;br /&gt;
&lt;br /&gt;
=== Run the tool ===&lt;br /&gt;
&lt;br /&gt;
Run Dynamic Xtreme from its own folder.&lt;br /&gt;
&lt;br /&gt;
* On Windows, double-click &amp;lt;code&amp;gt;dxt.exe&amp;lt;/code&amp;gt;.&lt;br /&gt;
* On Linux, open a terminal in the Dynamic Xtreme folder and run:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./dxt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The tool will ask a series of questions to configure the installation.&lt;br /&gt;
&lt;br /&gt;
=== Configure paths ===&lt;br /&gt;
&lt;br /&gt;
Your paths and selected features are saved in &amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt; inside the Dynamic Xtreme folder. The tool uses this file to retrieve your configuration for later installations.&lt;br /&gt;
&lt;br /&gt;
You can type each path or drag the corresponding file into the terminal. Then press Enter to continue.&lt;br /&gt;
&lt;br /&gt;
If you leave an answer blank and press Enter, Dynamic Xtreme uses the value saved in &amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt;. If no value has been saved and the path is optional, that integration is skipped.&lt;br /&gt;
&lt;br /&gt;
Paths are requested in this order:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Input ROM&#039;&#039;&#039;&lt;br /&gt;
#: Select the Super Mario World ROM you want to modify.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Output ROM&#039;&#039;&#039;&lt;br /&gt;
#: Enter the path of the ROM that will contain the installation result.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;PIXI executable&#039;&#039;&#039;&lt;br /&gt;
#: Select the PIXI executable. This path allows Dynamic Xtreme&#039;s&lt;br /&gt;
#: routines and defines to be integrated with PIXI.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;UberASMTool executable&#039;&#039;&#039;&lt;br /&gt;
#: Select the UberASMTool executable if your project uses&lt;br /&gt;
#: UberASM code.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;GPS executable&#039;&#039;&#039;&lt;br /&gt;
#: Select the GPS executable if your project uses&lt;br /&gt;
#: custom blocks.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;PIXI list&#039;&#039;&#039;&lt;br /&gt;
#: Select the list file where you registered the sprites&lt;br /&gt;
#: your project will use.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;UberASMTool list&#039;&#039;&#039;&lt;br /&gt;
#: Select the list file where you registered the UberASM&lt;br /&gt;
#: code your project will use.&lt;br /&gt;
&lt;br /&gt;
The PIXI, UberASMTool, and GPS paths and their lists are optional. If you do not use a tool and no path has been saved, leave its answer blank.&lt;br /&gt;
&lt;br /&gt;
To stop using an integration with saved paths, edit &amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt; and set its values to empty strings (&amp;lt;code&amp;gt;&amp;quot;&amp;quot;&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
* PIXI: &amp;lt;code&amp;gt;PixiPath&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PixiListPath&amp;lt;/code&amp;gt;.&lt;br /&gt;
* UberASMTool: &amp;lt;code&amp;gt;UberasmToolPath&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;UberasmListPath&amp;lt;/code&amp;gt;.&lt;br /&gt;
* GPS: &amp;lt;code&amp;gt;GPSPath&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Do not delete the fields or replace the entire file. You can then leave those paths blank in subsequent prompts without restoring the previous integration.&lt;br /&gt;
&lt;br /&gt;
=== Select features ===&lt;br /&gt;
&lt;br /&gt;
After configuring the paths, Dynamic Xtreme asks which features you want to install.&lt;br /&gt;
&lt;br /&gt;
Answer &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt; to enable a feature or&lt;br /&gt;
&amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to disable it.&lt;br /&gt;
&lt;br /&gt;
If you press Enter without typing anything, the value saved in &amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt; is retained. On the first installation, the feature&#039;s default value is used.&lt;br /&gt;
&lt;br /&gt;
For a typical installation, you can enable features without warnings. If a red warning appears, read it carefully and check compatibility with your project before enabling that feature.&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic_Xtreme#Features|Features]] for what each option does, and [[Dynamic_Xtreme#Compatibility|Compatibility]] for possible resource conflicts and RAM usage.&lt;br /&gt;
&lt;br /&gt;
=== Typical installation example with PIXI and UberASMTool ===&lt;br /&gt;
&lt;br /&gt;
This example uses PIXI and UberASMTool with the default options. The Windows paths are fictional; replace them with your project&#039;s paths. On Linux, provide the paths to the corresponding executables.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Prompt !! Example answer&lt;br /&gt;
|-&lt;br /&gt;
| Input ROM || &amp;lt;code&amp;gt;C:\MiHack\MiHack.smc&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Output ROM || &amp;lt;code&amp;gt;C:\MiHack\MiHack_DX.smc&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| PIXI executable || &amp;lt;code&amp;gt;C:\MiHack\PIXI\pixi.exe&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| UberASMTool executable || &amp;lt;code&amp;gt;C:\MiHack\UberASMTool\UberASMTool.exe&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| GPS executable || Leave blank if unused and no path is saved.&lt;br /&gt;
|-&lt;br /&gt;
| PIXI list || &amp;lt;code&amp;gt;C:\MiHack\PIXI\list.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| UberASMTool list || &amp;lt;code&amp;gt;C:\MiHack\UberASMTool\list.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use these feature settings:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Enabled !! Answer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; || Yes || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; || Yes || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; || Yes || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt; || Yes || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; || Yes || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || Yes || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt; || Yes || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt; || Yes || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt; || No || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt; || No || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; || No || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; || No || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
On SA-1 ROMs, &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; is disabled automatically.&lt;br /&gt;
&lt;br /&gt;
Enter retains the saved value if you have used the tool before. To reproduce this configuration, answer &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; according to the table; defaults are used only when there is no previous selection.&lt;br /&gt;
&lt;br /&gt;
== Command-line installation ==&lt;br /&gt;
&lt;br /&gt;
After an interactive installation, Dynamic Xtreme saves your selected paths and features in&lt;br /&gt;
&amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can reuse this configuration for later installations without answering every question again.&lt;br /&gt;
&lt;br /&gt;
On Windows, open a terminal in the Dynamic Xtreme folder and run:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.\dxt.exe -use-settings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On Linux, run:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./dxt -use-settings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a saved path is no longer valid, Dynamic Xtreme returns to interactive mode to request the configuration.&lt;br /&gt;
&lt;br /&gt;
Available options:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Option&lt;br /&gt;
! Alias&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-use-settings&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;-us&amp;lt;/code&amp;gt;&lt;br /&gt;
| Uses the saved paths and features without displaying the&lt;br /&gt;
prompts again.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-verbose&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;-v&amp;lt;/code&amp;gt;&lt;br /&gt;
| Shows more detailed installation information.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-help&amp;lt;/code&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
| Shows help and the available options.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-version&amp;lt;/code&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
| Shows the installed Dynamic Xtreme version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Options can be combined. For example, to use the saved configuration and show detailed information:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Windows:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.\dxt.exe -use-settings -verbose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Linux:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./dxt -use-settings -verbose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To change paths or selected features, run Dynamic Xtreme without &amp;lt;code&amp;gt;-use-settings&amp;lt;/code&amp;gt; and answer the prompts again.&lt;br /&gt;
&lt;br /&gt;
== Finish the installation ==&lt;br /&gt;
&lt;br /&gt;
Interactive and command-line installations produce the same result.&lt;br /&gt;
&lt;br /&gt;
The installation result is saved in &amp;lt;code&amp;gt;log.txt&amp;lt;/code&amp;gt; next to the Dynamic Xtreme executable. This file contains all installation details.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme prepares the PIXI, UberASMTool, and GPS integrations but does not run those tools. After installing Dynamic Xtreme, run your project&#039;s external tools again on the output ROM.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;When to reinstall:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* If you change graphics, palettes, or &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; files, reinstall Dynamic Xtreme and then the tools that use those resources.&lt;br /&gt;
* If you add, remove, or modify the &amp;lt;code&amp;gt;;#incdyn&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;;#incdri&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;;#incpale&amp;lt;/code&amp;gt; resource includes in the ASM, also reinstall Dynamic Xtreme and then the tools that use those resources.&lt;br /&gt;
* If you only change the &amp;lt;code&amp;gt;*.asm&amp;lt;/code&amp;gt; code without changing those includes, you do not need to reinstall Dynamic Xtreme. Reinsert the code with the appropriate tool.&lt;br /&gt;
&lt;br /&gt;
When Dynamic Xtreme needs to be reinstalled, use this order:&lt;br /&gt;
&lt;br /&gt;
# Run Dynamic Xtreme to regenerate and install its resources.&lt;br /&gt;
# Run PIXI, UberASMTool, GPS, and any other&lt;br /&gt;
#: tool that uses Dynamic Xtreme&#039;s generated data again.&lt;br /&gt;
&lt;br /&gt;
This order matters because resource addresses and IDs may change each time Dynamic Xtreme runs.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=Dynamic_Xtreme&amp;diff=21392</id>
		<title>Dynamic Xtreme</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=Dynamic_Xtreme&amp;diff=21392"/>
		<updated>2026-10-25T21:54:58Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme is a tool for dynamic graphics and palettes in Super Mario World on the SNES. Built for the ROM hacking community, it lets graphics and colors change in real time during gameplay. Its dynamic graphics system is flexible and modular, with a focus on performance.&lt;br /&gt;
&lt;br /&gt;
A dynamic sprite loads resources, such as graphics or palettes, in real time during gameplay. A static sprite uses resources that were already loaded when the level began.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme does not break the SNES hardware limits: it works within them, optimizing memory use and transfers to reduce their impact and make them much less noticeable during gameplay.&lt;br /&gt;
&lt;br /&gt;
Its main features include:&lt;br /&gt;
* Real-time (on-the-fly) graphics and palette changes.&lt;br /&gt;
* The most powerful and flexible dynamic sprite system available for Super Mario World.&lt;br /&gt;
* An Advanced Drawing System that can draw any registered frame on screen, with full control over priority, layer, offsets, and properties.&lt;br /&gt;
* Advanced palette effects, including real-time changes to hue, saturation, brightness, color blending, smooth transitions, and individual RGB and HSL channels.&lt;br /&gt;
* Complete replacement of player graphics and palettes, supporting any Mario size, any number of frames, and any animation style.&lt;br /&gt;
* Yoshi graphics replacement using a layout like the original game&#039;s.&lt;br /&gt;
* Extensive NMI handler optimizations to maximize performance.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme&#039;s features are selected during installation so a project can use only what it needs. Some have dependencies, compatibility issues, or restrictions on uninstalling them; check each option&#039;s warnings. The tool aims to make complex visual effects easier to implement in Super Mario World hacks while maintaining a high level of compatibility and stability.&lt;br /&gt;
&lt;br /&gt;
== Project goals ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme&#039;s main goal is to make dynamic sprites easier to use and provide full support for real-time graphics, palette, and tilemap changes.&lt;br /&gt;
&lt;br /&gt;
The project aims to make the most of the SNES without requiring advanced knowledge of the console&#039;s internal hardware. Traditional dynamic systems are often complex and rely heavily on technical concepts such as VRAM, CGRAM, OAM, and DMA. Dynamic Xtreme hides much of that complexity behind more modern, readable tools and formats that are easier to use.&lt;br /&gt;
&lt;br /&gt;
Another main goal is to maintain high performance even in visually complex situations, allowing extensive use of dynamic graphics, palette effects, and advanced drawing systems without unnecessarily compromising performance.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme also aims to make dynamic sprites as natural and straightforward to use as regular sprites. People focused on level design or content creation should be able to work with dynamic resources without constantly worrying about the system&#039;s internal technical limitations.&lt;br /&gt;
&lt;br /&gt;
== Features ==&lt;br /&gt;
&lt;br /&gt;
During installation, you can choose which features to enable. The names in parentheses match the installer options and &amp;lt;code&amp;gt;Settings.json&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Graphics, poses, and palettes ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Graphics changes (&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;) || Allows graphics to be loaded during gameplay. This is the foundation for tile animations, level graphics changes, and dynamic poses.&lt;br /&gt;
|-&lt;br /&gt;
| Palette changes (&amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;) || Allows palettes to be loaded and managed during gameplay. Includes automatic palette assignment so sprites can share the same colors without loading them multiple times.&lt;br /&gt;
|-&lt;br /&gt;
| Dynamic poses (&amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;) || Manages VRAM space as a pose cache: reuses loaded poses, shares them between entities, and chooses which ones to replace when more space is needed. This avoids unnecessary loads.&lt;br /&gt;
|-&lt;br /&gt;
| Pose drawing (&amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;) || Draws both dynamic and static poses defined in DrawInfo files. Allows control over their tiles, position, flipping, palette, and drawing priority.&lt;br /&gt;
|-&lt;br /&gt;
| Palette effects (&amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;) || Changes colors using RGB and HSL effects: tinting palettes, adjusting hue, saturation, or lightness, and making transitions between palettes. Effects can apply to individual resources or globally.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Dynamic pose loading and drawing are separate systems: you can draw a static pose without loading its graphics dynamically.&lt;br /&gt;
&lt;br /&gt;
=== Player and Yoshi ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Player features (&amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;) || Allows player graphics and palettes to be changed and adapts player drawing and pose loading for custom systems. Also allows the player to be hidden or dynamic uploads to be disabled. May conflict with patches that modify player graphics or palettes; read the installer warning before enabling it.&lt;br /&gt;
|-&lt;br /&gt;
| Yoshi features (&amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;) || Allows Yoshi&#039;s graphics to be changed while retaining the original pose layout. Requires &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; and shares its compatibility restrictions.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory and optimizations ===&lt;br /&gt;
&lt;br /&gt;
These options reorganize some of the game&#039;s work to leave more time for graphics and palette transfers. NMI is the routine that updates the display during the interval between frames.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Free the &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt; area (&amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;) || On ROMs without SA-1, avoids keeping certain original player, Yoshi, and animation graphics in RAM and reads them from ROM instead. Dynamic Xtreme uses the recovered space for its internal variables; it is not freely available for other uses without reservation. This option does not apply to SA-1 ROMs.&lt;br /&gt;
|-&lt;br /&gt;
| Controller optimization (&amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;) || Moves controller processing out of NMI to leave more time for display updates.&lt;br /&gt;
|-&lt;br /&gt;
| Fixed color optimization (&amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;) || Reduces NMI work for updating the fixed color used by the game&#039;s color math.&lt;br /&gt;
|-&lt;br /&gt;
| Kevin&#039;s Lunar Magic VRAM optimization (&amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;) || Integrates Kevin&#039;s optimization for Lunar Magic VRAM updates and moves some of its processing out of NMI. Use this version instead of installing the original patch separately. Once installed, it must not be uninstalled: doing so can break the ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Status bar optimization (&amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt;) || Reduces the original status bar&#039;s NMI work. Incompatible with resources that replace or modify it, such as custom status bars or patches that remove it.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For options that may conflict with other resources and the RAM used by the system, see [[#Compatibility|Compatibility]].&lt;br /&gt;
&lt;br /&gt;
Some features depend on others: &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; requires &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; requires &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; requires both graphics and palette changes; and &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; requires &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Quick installation guide:&#039;&#039;&#039; [[Dynamic_Xtreme_Quick_Start|Quick Start]]&lt;br /&gt;
&lt;br /&gt;
== Tools and support ==&lt;br /&gt;
&lt;br /&gt;
Pending&lt;br /&gt;
&lt;br /&gt;
== Files and formats ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Related article:&#039;&#039;&#039; [[Dynamic_Xtreme_files_and_formats|Dynamic Xtreme files and formats]]&lt;br /&gt;
&lt;br /&gt;
== Dynamic sprite creation guide ==&lt;br /&gt;
&lt;br /&gt;
To learn how to prepare, program, load, and draw a dynamic sprite, see the [[Dynamic_Xtreme_sprite_creation_guide|Dynamic Xtreme dynamic sprite creation guide]].&lt;br /&gt;
&lt;br /&gt;
== Dynamic Xtreme with UberASM ==&lt;br /&gt;
&lt;br /&gt;
The [[Dynamic_Xtreme_UberASM_guide|Dynamic Xtreme UberASM guide]] shows how to reserve palettes, configure dynamic sprite space and the per-frame data limit, create animations, change player graphics, and apply palette effects.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
&lt;br /&gt;
The [[Dynamic_Xtreme_ASM_API|ASM API reference]] explains how to use Dynamic Xtreme&#039;s variables, defines, routines, and macros. It covers each call&#039;s inputs and results, with examples for poses, drawing, palettes, color effects, and graphics transfers, as well as multiplication and division macros.&lt;br /&gt;
&lt;br /&gt;
== How the system works ==&lt;br /&gt;
&lt;br /&gt;
The article on [[Dynamic_Xtreme_internal_workings|Dynamic Xtreme&#039;s internal workings]] explains the organization of NMI and game modes, graphics and palette loading, pose drawing, optimizations, the dynamic pose cache, and palette effects.&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
In general, features without installer warnings do not usually have compatibility problems with other resources. These are:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This does not guarantee that every resource combination will work: two pieces of code may still use the same RAM, the same VRAM space, or modify the same game routine. Also, &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; requires &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, so the latter&#039;s restrictions still apply.&lt;br /&gt;
&lt;br /&gt;
=== Features with compatibility restrictions ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Optional feature !! Possible conflicts and what to do&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; || May conflict with &#039;&#039;&#039;LX5&#039;s Powerups&#039;&#039;&#039;, &#039;&#039;&#039;Player 8x8 tiles DMAer&#039;&#039;&#039;, &#039;&#039;&#039;Player 32x32&#039;&#039;&#039;, and other systems that replace player graphics or palette loading. &#039;&#039;&#039;Player Revolution&#039;&#039;&#039; is compatible. If your player system needs those original routines, leave this option disabled; you must also disable &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; || Depends on &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; and inherits its compatibility restrictions, even though it has no separate warning. If a resource is incompatible with &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, enabling only &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; cannot avoid the conflict: leave both disabled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt; || Incompatible with resources that modify, replace, or remove the original status bar, such as &#039;&#039;&#039;LX5&#039;s DKC Style Status Bar&#039;&#039;&#039;, &#039;&#039;&#039;Minimalistic Status Bar&#039;&#039;&#039;, and &#039;&#039;&#039;Nuke Status Bar&#039;&#039;&#039;. Leave this optimization disabled if you use one of them.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt; || Integrates Kevin&#039;s Lunar Magic VRAM optimization patch: use this version instead of installing the original separately. Its warning also states that it &#039;&#039;&#039;must not be uninstalled after installation&#039;&#039;&#039;, because doing so can break the ROM. To revert it, restore a backup made before installation.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These features are optional: leave a conflicting feature disabled and continue using Dynamic Xtreme&#039;s other systems, respecting their dependencies. Disabling an option does not undo another patch&#039;s changes or remove the uninstall restriction on &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== RAM usage ===&lt;br /&gt;
&lt;br /&gt;
The main addresses are configured in &amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt; inside the Dynamic Xtreme directory. In the repository, this is &amp;lt;code&amp;gt;DynamicXtremeLibrary/ASM/DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The space used depends on the enabled features and whether the ROM uses SA-1. The following ranges include both endpoints and were calculated with &#039;&#039;&#039;all features that reserve RAM enabled&#039;&#039;&#039;, &amp;lt;code&amp;gt;!VRAMTransferSize = 64&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;!CGRAMTransferSize = 64&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuration !! &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; block !! Size !! &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; block !! Size&lt;br /&gt;
|-&lt;br /&gt;
| LoROM with &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2000–$7E2500&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7E2800–$7E3608&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM without &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB440–$7FB940&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7F9C80–$7FAA88&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C000–$40C47E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$047F&amp;lt;/code&amp;gt;: 1151 bytes || &amp;lt;code&amp;gt;$418AFF–$419907&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two internal blocks total &#039;&#039;&#039;4874 bytes on LoROM&#039;&#039;&#039; and &#039;&#039;&#039;4744 bytes on SA-1&#039;&#039;&#039;. The difference comes from the drawing system&#039;s 130 bytes, which are reserved only on LoROM. The gap between the blocks is not automatically occupied.&lt;br /&gt;
&lt;br /&gt;
Disabling a feature removes its conditional reservations and shifts the addresses that follow. Increasing &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; also increases their table sizes.&lt;br /&gt;
&lt;br /&gt;
==== Sprite tables ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; &#039;&#039;&#039;are not available for your own variables&#039;&#039;&#039;: the sprite tables from &amp;lt;code&amp;gt;DynamicXSpritesTables.asm&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;MoreSpriteMiscs.asm&amp;lt;/code&amp;gt; begin there. You must also reserve them when using those resources.&lt;br /&gt;
&lt;br /&gt;
With the same configuration as the table above, their ranges are:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuration !! Tables starting at &amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; !! Size !! Tables starting at &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; !! Size&lt;br /&gt;
|-&lt;br /&gt;
| LoROM with &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2501–$7E26EC&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7E3609–$7E3824&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM without &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB941–$7FBB2C&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7FAC82–$7FAE9D&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C47F–$40C6D8&amp;lt;/code&amp;gt; || 602 bytes || &amp;lt;code&amp;gt;$419908–$419BCD&amp;lt;/code&amp;gt; || 710 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Including these tables, the described space totals &#039;&#039;&#039;5906 bytes on LoROM&#039;&#039;&#039; and &#039;&#039;&#039;6056 bytes on SA-1&#039;&#039;&#039;. Tables are calculated for 12 normal sprites on LoROM and 22 on SA-1, plus the corresponding cluster, extended, and smoke slots.&lt;br /&gt;
&lt;br /&gt;
Normally, &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; starts immediately after the second internal block. On LoROM without &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, it is placed separately using &amp;lt;code&amp;gt;!Variables3 = $7FAC82&amp;lt;/code&amp;gt;, so its tables do not immediately follow &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme also uses the existing fixed color and palette mirrors: &amp;lt;code&amp;gt;$7E0701&amp;lt;/code&amp;gt; (2 bytes) and &amp;lt;code&amp;gt;$7E0703&amp;lt;/code&amp;gt; (512 bytes) on LoROM. Their declared SA-1 addresses are &amp;lt;code&amp;gt;$406701&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$006703&amp;lt;/code&amp;gt;. These are neither additional reservations within the blocks above nor free addresses for your code.&lt;br /&gt;
&lt;br /&gt;
==== Relocating RAM to resolve a conflict ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning:&#039;&#039;&#039; relocating these variables requires knowing which address to choose and accounting for the full memory footprint. A free starting address is not enough: the entire block must fit, and the routines must be able to access it. If you are unfamiliar with this, consult someone experienced before changing the addresses.&lt;br /&gt;
&lt;br /&gt;
If another resource uses any of these areas, you can edit &#039;&#039;&#039;&amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt;&#039;&#039;&#039; to make Dynamic Xtreme use other available space in your ROM hack.&lt;br /&gt;
&lt;br /&gt;
* Change &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; in the configuration matching your ROM: LoROM with &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, LoROM without it, or SA-1.&lt;br /&gt;
* On LoROM without &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, also check &amp;lt;code&amp;gt;!Variables3&amp;lt;/code&amp;gt;, which determines where the &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; tables begin.&lt;br /&gt;
* Reserve enough space for the entire block and the sprite tables that follow. A free first address alone is not enough.&lt;br /&gt;
* Respect the memory map and the banks required by the routines. Not every free address works with every type of access.&lt;br /&gt;
* After changing the addresses, reinstall Dynamic Xtreme and reinsert PIXI, UberASM, and any other resources that use its defines.&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, Dynamic Xtreme uses the RAM recovered by relocating the original graphics; do not share it with other resources without checking which part is used. Without that option, the alternative addresses may overlap those of other common resources. SA-1 uses its own addresses and disables &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Edit the file in the &#039;&#039;&#039;ASM&#039;&#039;&#039; directory, not the generated copies in &amp;lt;code&amp;gt;ExtraDefines&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Patch/ExtraDefines&amp;lt;/code&amp;gt;: those copies are regenerated during installation.&lt;br /&gt;
&lt;br /&gt;
== Resources made with Dynamic Xtreme ==&lt;br /&gt;
&lt;br /&gt;
Resources developed for Dynamic Xtreme are not usually published on traditional sites such as SMW Central, because many depend directly on the framework and its advanced systems.&lt;br /&gt;
&lt;br /&gt;
Instead, Dynamic Xtreme resources, examples, systems, and related projects are mainly collected at:&lt;br /&gt;
&lt;br /&gt;
https://snestorage.dev&lt;br /&gt;
&lt;br /&gt;
There you can find sprites, player systems, graphical effects, technical examples, and other resources designed specifically for Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aims to modernize and simplify dynamic systems in Super Mario World, offering more flexible, powerful, and accessible tools while retaining compatibility and advanced control.&lt;br /&gt;
&lt;br /&gt;
The project continues to evolve with new optimizations, formats, and tools for both experienced users and people just starting to work with dynamic graphics on SNES.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme&#039;s main aim is to support increasingly complex resources and systems while keeping the workflow cleaner, easier to maintain, and more accessible to the community.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21388</id>
		<title>es/Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21388"/>
		<updated>2026-10-25T18:22:25Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo funciona Dynamic Xtreme, desde la preparación de los recursos al instalarlo hasta la carga y el dibujo de una pose durante el juego.&lt;br /&gt;
&lt;br /&gt;
== Qué prepara la instalación ==&lt;br /&gt;
&lt;br /&gt;
Antes de que un sprite pueda usar sus gráficos o una paleta, Dynamic Xtreme tiene que guardarlos en la ROM y preparar la información para encontrarlos. Lo mismo ocurre con cualquier otro recurso dinámico que hayas añadido.&lt;br /&gt;
&lt;br /&gt;
Para hacerlo, la herramienta lee los DynamicInfo, DrawInfo y PaletteEffect. Cada archivo aporta una parte distinta: qué recursos se van a cargar, cómo se dibujan las poses y qué cambios de color se pueden aplicar.&lt;br /&gt;
&lt;br /&gt;
Gracias a esta preparación se generan defines en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permiten utilizar los recursos y ejecutar fácilmente las rutinas necesarias.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: recursos y datos de carga ===&lt;br /&gt;
&lt;br /&gt;
Un DynamicInfo reúne los gráficos de poses, las paletas y los recursos generales que necesita un sprite u otro código. Si incluye gráficos de poses dinámicas, la herramienta los organiza para que puedan cargarse con la distribución de tiles que espera el sistema.&lt;br /&gt;
&lt;br /&gt;
Por cada pose guarda varios datos en tablas separadas. Todas mantienen el mismo orden: la entrada de una pose en una tabla corresponde a esa misma pose en las demás. En la tabla siguiente, &#039;&#039;&#039;N&#039;&#039;&#039; es la cantidad de poses dinámicas instaladas.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || 2 × N || 2 || La cantidad de datos que utiliza cada pose, en bytes. Se utiliza para comprobar si su carga cabe en el presupuesto del frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || N || 1 || Cuántos bloques de 16×16 hay que reservar en VRAM para la pose. No siempre coincide exactamente con los bytes que se copian, porque una pieza incompleta también puede necesitar un bloque de espacio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 × N || 3 || La dirección de los gráficos de cada pose en ROM. Incluye el banco, de modo que el código de carga pueda encontrar su origen completo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 × N || 2; dos valores por pose || Dos tamaños por pose, correspondientes a los dos tramos en que pueden dividirse sus gráficos. La rutina de carga utiliza esos tamaños para repartirlos correctamente en VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 × N || 2 || El desplazamiento en VRAM desde el comienzo del primer tramo hasta el comienzo del segundo. Permite colocar el segundo tramo donde corresponde, aunque el primero termine con una fila incompleta.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas describen todas las poses instaladas, no solo las que están en pantalla. Más adelante, la caché guarda por separado cuáles están cargadas y dónde quedaron.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si se solicita una pose que todavía no está en VRAM, el sistema consulta cuántos bytes necesita cargar, busca espacio para sus bloques y utiliza la dirección y los datos de sus tramos para preparar la carga.&lt;br /&gt;
&lt;br /&gt;
==== Tablas de paletas ====&lt;br /&gt;
&lt;br /&gt;
Las paletas declaradas en los DynamicInfo se reúnen en &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. Si &#039;&#039;&#039;P&#039;&#039;&#039; es la cantidad de entradas de las listas de paletas de los DynamicInfo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; || 2 × P || 2 || ID de cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; || 3 × P || 3 || Dirección de sus colores en ROM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
P cuenta las entradas de las listas, no solo las paletas distintas: una paleta compartida puede aparecer en más de un DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
Las dos listas siguen el orden de las paletas de los DynamicInfo. El define de offset de cada DynamicInfo indica dónde comienza su lista dentro de ellas. Al elegir una versión, el sistema suma ese índice al offset y obtiene tanto el ID como la dirección de los colores elegidos.&lt;br /&gt;
&lt;br /&gt;
El ID permite reconocer y compartir una paleta; la dirección permite cargarla. No son el número de paleta de pantalla: una misma paleta instalada puede terminar, por ejemplo, en la paleta 9 o en la C según la asignación.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y defines ====&lt;br /&gt;
&lt;br /&gt;
Los archivos declarados en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; se guardan en ROM. Su dirección y la cantidad de bytes que ocupan pueden consultarse mediante los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Por ejemplo, para &amp;lt;code&amp;gt;my_resource.bin&amp;lt;/code&amp;gt; se generan:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt;: dirección del recurso en ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt;: cantidad de bytes que ocupa.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt;: ID del recurso.&lt;br /&gt;
&lt;br /&gt;
El nombre se normaliza en PascalCase: se eliminan espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: datos y rutinas de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El DrawInfo describe cómo está formada una pose: qué tiles tiene, dónde se coloca cada uno, qué tamaño utiliza y cómo cambia al voltearse.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, Dynamic Xtreme genera rutinas de dibujo optimizadas según los parámetros que utilizan los tiles. Tiene en cuenta, por ejemplo, si necesitan desplazamientos X e Y, si comparten el mismo tamaño, si utilizan propiedades comunes y si requieren volteos.&lt;br /&gt;
&lt;br /&gt;
De esta forma, la rutina realiza el trabajo que necesita ese dibujo sin añadir el manejo de opciones que no utiliza. Varias poses pueden compartirla si necesitan el mismo tratamiento; eso no significa que compartan también sus gráficos o su ID.&lt;br /&gt;
&lt;br /&gt;
La relación entre una pose y su dibujo se guarda en estas tablas. &#039;&#039;&#039;D&#039;&#039;&#039; es la cantidad de poses de dibujo y &#039;&#039;&#039;R&#039;&#039;&#039; la cantidad de rutinas generadas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || 2 × D || 2 || Dónde comienzan los datos de la pose dentro de las tablas de su rutina de dibujo. Así se localizan sus tiles y desplazamientos sin recorrer las poses anteriores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || D || 1 || La cantidad de tiles de la pose menos uno. Una pose de cuatro tiles guarda 3; la rutina utiliza ese valor para recorrer sus piezas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || D || 1 || Qué rutina de dibujo utiliza cada pose. Las poses con características compatibles pueden apuntar al mismo ID de rutina.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || 3 × R || 3 por rutina || Las direcciones de las rutinas de dibujo. El ID de rutina permite encontrar aquí el código que debe ejecutarse.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada rutina tiene, además, las tablas que necesitan sus poses. Aquí &#039;&#039;&#039;T&#039;&#039;&#039; es la cantidad de entradas de cada tabla de la rutina:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos !! Bytes totales !! Bytes por valor !! Qué describen&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || T, si se genera || 1 || Los números de tile que forman la pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || T, si se genera || 1 || Las propiedades de cada pieza, como los volteos y su prioridad respecto a las capas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || T por tabla, si se genera || 1 || La posición de cada tile respecto al punto de origen de la pose.&lt;br /&gt;
|-&lt;br /&gt;
| Tablas de desplazamientos para los volteos || T por tabla, si se genera || 1 || Las posiciones que deben utilizarse al voltear la pose cuando necesita una distribución distinta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || T, si se genera || 1 || El tamaño de cada tile: 8×8 o 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
No todas estas tablas tienen que aparecer en todas las rutinas. Si un dato es igual para todas las piezas o puede obtenerse de un valor común, la herramienta puede generar una rutina que lo utilice directamente.&lt;br /&gt;
&lt;br /&gt;
La optimización se hace durante la instalación. Si todos los tiles tienen el mismo tamaño, por ejemplo, la rutina puede utilizar ese valor común sin leer un tamaño distinto para cada pieza.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: datos de los efectos ===&lt;br /&gt;
&lt;br /&gt;
Un archivo PaletteEffect contiene una lista de cambios de color. La instalación les asigna IDs y guarda sus datos en &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Como en las tablas de poses, los datos de cada efecto mantienen la misma posición en las distintas listas. Los IDs de efectos comienzan en 1; el ID 0 se utiliza para indicar que no hay efecto global. En la tabla, &#039;&#039;&#039;E&#039;&#039;&#039; es la cantidad de efectos instalados; el conjunto ocupa &#039;&#039;&#039;2 + 7 × E bytes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parte de la tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || 2 || 2 || La cantidad de efectos instalados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || E || 1 || El tipo de cada efecto, por ejemplo &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Indica qué cálculo debe realizarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || E por tabla; 3 × E entre las tres || 1 por tabla || Los valores de los canales que utiliza el efecto. En una transición, estos tres bytes guardan la dirección de la paleta de destino, no valores de canales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || E por tabla; 3 × E entre las tres || 1 por tabla || Cuánto se aplica el cambio en cada componente. Van de 0 a 127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Si el efecto es una transición hacia otra paleta, la herramienta también prepara esa paleta. Convierte sus colores al formato RGB o HSL que necesita la transición y los guarda en ROM. Durante el juego se puede utilizar ese destino sin tener que convertirlo de nuevo en cada llamada.&lt;br /&gt;
&lt;br /&gt;
Estas paletas de transición son distintas de las paletas normales que se cargan a CGRAM: contienen tres componentes por color y se utilizan para calcular el efecto.&lt;br /&gt;
&lt;br /&gt;
=== Cómo encuentra el código los recursos instalados ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; publica los IDs, direcciones, tamaños y offsets que necesitan los recursos. Por ejemplo, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifica una pose y &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifica el primer efecto de un archivo.&lt;br /&gt;
&lt;br /&gt;
Los nombres se normalizan en PascalCase: se eliminan separadores como espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra. &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, por ejemplo, pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También se genera &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, que guarda las direcciones de los bloques donde se insertaron los recursos. Cada dirección ocupa 3 bytes y se añade un valor final &amp;lt;code&amp;gt;$FFFFFF&amp;lt;/code&amp;gt; de otros 3 bytes. Para B bloques, ocupa &amp;lt;code&amp;gt;3 × (B + 1)&amp;lt;/code&amp;gt; bytes. La herramienta utiliza esa información para localizar los datos de una instalación anterior al reinstalar.&lt;br /&gt;
&lt;br /&gt;
Una reinstalación puede cambiar IDs y direcciones. Por eso hay que volver a insertar los sprites, bloques y códigos UberASM que utilizan los defines generados.&lt;br /&gt;
&lt;br /&gt;
== El trabajo de cada frame ==&lt;br /&gt;
&lt;br /&gt;
En la lógica principal se ejecutan el jugador, los sprites y los demás códigos del modo de juego. Los que utilizan Dynamic Xtreme solicitan las poses y paletas que necesitan, preparan los efectos locales y llaman a las rutinas de dibujo. Las cargas que se aceptan quedan anotadas para transferir sus datos durante NMI.&lt;br /&gt;
&lt;br /&gt;
Al terminar esa lógica, el código de game mode de Dynamic Xtreme realiza las tareas que correspondan a las opciones habilitadas: prepara las actualizaciones de VRAM de la optimización de Kevin, mantiene el estado de las paletas y calcula los efectos globales pendientes.&lt;br /&gt;
&lt;br /&gt;
Después, durante NMI, Dynamic Xtreme realiza estas tareas en orden, según las funcionalidades habilitadas:&lt;br /&gt;
&lt;br /&gt;
# Pone &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; en 0.&lt;br /&gt;
# Incrementa &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Incrementa &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; si la acción no está congelada ni el juego está en pausa.&lt;br /&gt;
# Ejecuta las transferencias de gráficos a VRAM.&lt;br /&gt;
# Ejecuta las transferencias de colores a CGRAM.&lt;br /&gt;
# Actualiza el color 0,0 si el sistema de efectos tiene un resultado pendiente.&lt;br /&gt;
&lt;br /&gt;
El orden que seguiremos para explicarlo es, por tanto, &#039;&#039;&#039;lógica principal → tareas al terminar el game mode → transferencias durante NMI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Lógica principal ===&lt;br /&gt;
&lt;br /&gt;
Cada recurso decide qué necesita. Un sprite puede cambiar de pose, una animación puede pedir nuevos gráficos y un código UberASM puede cargar una paleta o seleccionar un efecto.&lt;br /&gt;
&lt;br /&gt;
Si la pose solicitada ya está cargada, Dynamic Xtreme actualiza su tiempo de último uso para protegerla del reemplazo y no vuelve a cargar sus gráficos. Si no está cargada, comprueba el presupuesto de datos del frame y busca espacio disponible en VRAM antes de preparar su carga.&lt;br /&gt;
&lt;br /&gt;
El dibujo también se prepara en esta parte: las rutinas escriben en los buffers OAM la posición, los tiles y las propiedades de las piezas que se mostrarán.&lt;br /&gt;
&lt;br /&gt;
Una solicitud puede rechazarse, por ejemplo si no queda presupuesto para sus datos. El recurso que la pidió debe comprobar el resultado y decidir si conserva lo anterior o vuelve a intentarlo después. Una carga rechazada no queda guardada automáticamente para otro frame.&lt;br /&gt;
&lt;br /&gt;
=== Tareas de game mode ===&lt;br /&gt;
&lt;br /&gt;
En esta parte se realizan las siguientes tareas, según las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antes de ejecutar la lógica del juego:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitado &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;, se ejecuta la rutina del control aquí en lugar de hacerlo en NMI.&lt;br /&gt;
# Se comprueba si Dynamic Xtreme debe funcionar en el game mode actual. Si no debe hacerlo, se reinician sus variables. Esto ocurre cada frame que se permanezca en un modo no permitido.&lt;br /&gt;
&lt;br /&gt;
Después se ejecuta la lógica normal del juego, incluidos los sprites y los códigos que solicitan cargas o cambios de paleta.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cuando termina esa lógica:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitada la optimización de VRAM de Kevin, se ajustan los destinos de las actualizaciones de Lunar Magic antes de que se transfieran.&lt;br /&gt;
# Se ponen en 0 los indicadores de actualización de las paletas y se resta 1 a sus temporizadores de protección si todavía son mayores que 0. Esta parte se omite durante la pausa y en los modos no permitidos.&lt;br /&gt;
# Se aplican los efectos globales a las paletas que necesitan actualizarse y se preparan las transferencias de sus colores. Esta parte también se omite si la comprobación anterior impide continuar.&lt;br /&gt;
&lt;br /&gt;
Las copias a VRAM y CGRAM se realizan después, durante NMI. Aquí se deja preparado lo que se va a copiar.&lt;br /&gt;
&lt;br /&gt;
=== Game modes permitidos ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme utiliza dos comprobaciones de game mode:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Sistema general:&#039;&#039;&#039; &amp;lt;code&amp;gt;Routines_AllowedGameMode&amp;lt;/code&amp;gt;, publicado como &amp;lt;code&amp;gt;!AllowedGameMode&amp;lt;/code&amp;gt;. Se utiliza para decidir si se reinicializa el sistema, si se procesa su NMI y si se realizan las tareas de paletas. Las macros de asignación de paletas también consultan esta comprobación cuando necesitan procesar una carga del DynamicInfo.&lt;br /&gt;
* &#039;&#039;&#039;Rutinas de sprites:&#039;&#039;&#039; &amp;lt;code&amp;gt;DXAllowedGameMode&amp;lt;/code&amp;gt; utiliza una tabla distinta. La carga de poses mediante &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; y sus macros generales tiene una tabla con los mismos valores para decidir si procesa una solicitud nueva.&lt;br /&gt;
&lt;br /&gt;
Por tanto, que el sistema general esté habilitado no significa que todas las funciones de sprites acepten cargas nuevas en ese modo. Esta tabla muestra las comprobaciones actuales; los IDs están en hexadecimal:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Game mode !! Pantalla o etapa de SMW !! Sistema general !! DXAllowedGameMode / solicitudes nuevas de Upload&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt; || Apertura del foco de la pantalla de título. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || Pantalla de título. || Sí || Sí&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || Selección de partida. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$09&amp;lt;/code&amp;gt; || Borrado de partida. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt; || Selección de uno o dos jugadores. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; || Carga del overworld. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0D&amp;lt;/code&amp;gt; || Aparición gradual del overworld. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; || Overworld. || Sí || Sí&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt; || Preparación del nivel. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$13&amp;lt;/code&amp;gt; || Aparición gradual del nivel. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || Juego dentro del nivel. || Sí || Sí&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$15&amp;lt;/code&amp;gt; || Desvanecimiento hacia Game Over / Time Up. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; || Escena de castillo o créditos. || No || Sí&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt; || Desvanecimiento hacia la casa de Yoshi de los créditos. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1D&amp;lt;/code&amp;gt; || Carga de la casa de Yoshi de los créditos. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt; || Aparición gradual de la casa de Yoshi de los créditos. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1F&amp;lt;/code&amp;gt; || Casa de Yoshi de los créditos. || Sí || Sí&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$24&amp;lt;/code&amp;gt; || Aparición gradual de la presentación de enemigos. || Sí || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt; || Presentación de enemigos de los créditos. || Sí || Sí&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$29&amp;lt;/code&amp;gt; || Pantalla «The End». || No || Sí&lt;br /&gt;
|-&lt;br /&gt;
| Los demás valores entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$2F&amp;lt;/code&amp;gt;. || — || No || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres de las etapas corresponden a los [https://github.com/IsoFrieze/SMWDisX/blob/master/bank_00.asm game modes de SMW documentados en SMWDisX]; los permisos se obtienen de las tablas de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Cuando &amp;lt;code&amp;gt;Upload&amp;lt;/code&amp;gt; no permite una solicitud nueva, comprueba si el recurso conserva una pose anterior. Si existe, actualiza su tiempo de último uso y devuelve carry activado; si no existe, devuelve carry desactivado. No solicita otra pose en ese camino.&lt;br /&gt;
&lt;br /&gt;
Los modos &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$29&amp;lt;/code&amp;gt; muestran por qué deben distinguirse ambas columnas: pasar la comprobación de sprites no habilita el NMI del sistema general ni evita que el game mode reinicialice sus variables. La columna de sprites no debe interpretarse como una garantía de funcionamiento completo en esos modos.&lt;br /&gt;
&lt;br /&gt;
=== Transferencias durante NMI ===&lt;br /&gt;
&lt;br /&gt;
NMI es una interrupción que SNES puede generar al comenzar VBlank, después de dibujar la parte visible de la pantalla. El juego aprovecha ese intervalo para actualizar gráficos, colores y otros datos de video.&lt;br /&gt;
&lt;br /&gt;
En los modos permitidos, la rutina de Dynamic Xtreme realiza estas tareas en orden, según las funcionalidades habilitadas:&lt;br /&gt;
&lt;br /&gt;
# Pone &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; en 0 para contar las solicitudes del siguiente ciclo de lógica. Las transferencias ya preparadas siguen guardadas en sus listas.&lt;br /&gt;
# Incrementa &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Comprueba &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt;. Si ambos están en 0, incrementa &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ejecuta las transferencias pendientes a VRAM, si está habilitado &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ejecuta las transferencias pendientes a CGRAM, si está habilitado &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si está habilitado &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;, ejecuta la actualización del color 0,0 cuando hay un resultado pendiente.&lt;br /&gt;
&lt;br /&gt;
Para realizar las copias se utiliza DMA. NMI lee cada carga de las listas, configura desde dónde se copiarán los datos, cuántos bytes se copiarán y dónde se colocarán, y ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
El tiempo de VBlank es limitado y SMW también lo necesita para sus actualizaciones de pantalla. Para limitar la cantidad de datos enviados en un frame y evitar flickering, Dynamic Xtreme utiliza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, que cuenta los bytes de las cargas solicitadas, y &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, que establece el límite permitido. Antes de aceptar una carga normal, se comprueba que sus bytes no hagan superar ese límite.&lt;br /&gt;
&lt;br /&gt;
==== Las listas de transferencias ====&lt;br /&gt;
&lt;br /&gt;
Cada transferencia guarda el origen de los datos, su banco, la cantidad de bytes y el destino en VRAM o CGRAM.&lt;br /&gt;
&lt;br /&gt;
Al realizar las copias, NMI recorre las listas desde la última entrada hacia la primera y después las vacía. Esto no borra los gráficos o colores cargados: permanecen en su destino hasta que otro código los cambie.&lt;br /&gt;
&lt;br /&gt;
La lista de VRAM utiliza 0 cuando no tiene entradas. La de CGRAM utiliza &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, porque guarda el índice de la última entrada en lugar de guardar directamente su cantidad.&lt;br /&gt;
&lt;br /&gt;
Si dos códigos escriben sobre el mismo destino, deben coordinar sus cargas. El orden de las solicitudes no debe utilizarse como sustituto de decidir qué recurso puede ocupar cada espacio.&lt;br /&gt;
&lt;br /&gt;
Normalmente, el recurso se lee desde ROM. Si el recurso se encuentra en un buffer en RAM, el usuario debe conservar su contenido hasta que NMI realice la transferencia. Por ejemplo, si prepara una paleta en RAM, no debe modificar ni reutilizar ese buffer antes de que se copie. La lista guarda su dirección, no una copia de sus datos; Dynamic Xtreme no protege el buffer contra cambios realizados por otros códigos.&lt;br /&gt;
&lt;br /&gt;
==== Presupuesto de datos ====&lt;br /&gt;
&lt;br /&gt;
Las macros de transferencia, como &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt;, comprueban cuántos bytes se han solicitado mediante &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;. Si al añadir la nueva carga se supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, la rechazan. Si la aceptan, suman sus bytes al contador.&lt;br /&gt;
&lt;br /&gt;
El límite predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Su objetivo es evitar flickering por enviar demasiados datos en un mismo frame. Es un límite de cantidad de datos, no una medida exacta del tiempo que tarda cada transferencia.&lt;br /&gt;
&lt;br /&gt;
Estas macros tienen variantes como &amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ForcedTransferToCGRAM()&amp;lt;/code&amp;gt;, que aceptan la carga sin comprobar si supera el límite. Sus bytes también se suman a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, por lo que reducen lo que queda disponible para las siguientes cargas normales. Se utilizan para cargas prioritarias, como las del jugador; usarlas no evita el flickering si se solicita una cantidad excesiva de datos.&lt;br /&gt;
&lt;br /&gt;
Para consultar la diferencia entre el presupuesto de bytes y la capacidad de las listas, las restricciones de las transferencias y las comprobaciones que debe realizar tu código, consulta [[es/Dynamic_Xtreme_ASM_API#PPU|PPU en la API ASM]].&lt;br /&gt;
&lt;br /&gt;
==== Los dos relojes ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_Timer: protección de las solicitudes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza cuando se ejecuta la parte de NMI de Dynamic Xtreme. Además de medir cuánto lleva una pose sin utilizarse, sirve para evitar que un recurso repita sus solicitudes antes de que se procesen las anteriores.&lt;br /&gt;
&lt;br /&gt;
No siempre hay un ciclo de lógica por cada ejecución completa de NMI. Durante slowdown, SMW puede ejecutar una versión reducida de NMI, y puede haber dos ciclos de lógica sin que entre ellos se hayan procesado las listas de transferencias de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Sin una protección, un recurso podría añadir otra vez sus cargas a esas listas. Las solicitudes repetidas ocuparían más espacio y podrían provocar flickering.&lt;br /&gt;
&lt;br /&gt;
Para evitarlo, las rutinas de carga de poses para sprites comparan &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; con el valor de dos bytes guardado por ese sprite, normalmente llamado &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt;. En los aliases de sprites se utiliza &amp;lt;code&amp;gt;!SafeFrameLowByte,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!SafeFrameHighByte,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El proceso es el siguiente:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Compara los relojes.&#039;&#039;&#039; Si &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; coincide con &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;, ese sprite ya procesó su carga de poses con ese valor del reloj. La rutina omite una nueva solicitud.&lt;br /&gt;
# &#039;&#039;&#039;Guarda el intento antes de procesarlo.&#039;&#039;&#039; Si los valores son distintos, copia &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; y después comprueba si puede reutilizar la pose o necesita solicitar otra.&lt;br /&gt;
# &#039;&#039;&#039;Comprueba el resultado.&#039;&#039;&#039; Si necesita una pose nueva, la solicitud puede aceptarse o rechazarse. Aunque sea rechazada, el valor guardado en &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; no se deshace.&lt;br /&gt;
&lt;br /&gt;
Por tanto, &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; indica &#039;&#039;&#039;cuándo se procesó el último intento&#039;&#039;&#039;, no cuándo se consiguió cargar una pose. Si la carga falla, volver a ejecutar la rutina con el mismo &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; no permite intentarla otra vez, aunque entre ambas llamadas haya cambiado la pose deseada o el espacio disponible.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;, tanto una solicitud rechazada como una llamada omitida por esta protección utilizan el mismo camino de respaldo:&lt;br /&gt;
&lt;br /&gt;
* Si &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; es distinto de &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, actualizan el tiempo de último uso de esa pose para protegerla del reemplazo y devuelven carry activado. El sprite puede seguir dibujando la última pose disponible.&lt;br /&gt;
* Si contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no existe una pose de respaldo y devuelven carry desactivado.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, durante slowdown puede ocurrir esta secuencia:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;DX_Timer = $0030&amp;lt;/code&amp;gt;. El sprite guarda &amp;lt;code&amp;gt;$0030&amp;lt;/code&amp;gt; en su &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; e intenta obtener una pose nueva. No queda presupuesto de datos y la solicitud falla; conserva la pose anterior si tiene una.&lt;br /&gt;
# SMW ejecuta otro ciclo de lógica sin que se haya procesado el NMI de Dynamic Xtreme. El reloj sigue en &amp;lt;code&amp;gt;$0030&amp;lt;/code&amp;gt;. La siguiente llamada del mismo sprite detecta la coincidencia y no repite la solicitud.&lt;br /&gt;
# Cuando se ejecuta el NMI de Dynamic Xtreme, &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza a &amp;lt;code&amp;gt;$0031&amp;lt;/code&amp;gt;. En la siguiente llamada, los relojes ya no coinciden y el sprite puede volver a intentarlo. La solicitud rechazada no se reintenta sola: el código del sprite debe volver a llamar a la rutina.&lt;br /&gt;
&lt;br /&gt;
Esta protección está activada en los aliases de carga de poses para sprites. En [[es/Dynamic_Xtreme_ASM_API#GeneralUpload|GeneralUpload]] y [[es/Dynamic_Xtreme_ASM_API#Upload (macro general)|Upload (macro general)]] se controla con &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt;; el respaldo de la pose anterior se controla por separado con &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt;. [[es/Dynamic_Xtreme_ASM_API#TakeDynamicRequest|TakeDynamicRequest]] y las [[es/Dynamic_Xtreme_ASM_API#PPU|macros de transferencia PPU]] no realizan esta comprobación de &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt; por ti.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; continúa avanzando durante la pausa cuando se ejecuta esa parte de NMI.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_SyncTimer: animaciones sincronizadas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
La función principal de &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; es dar a los sprites un reloj común para sus animaciones. Por ejemplo, varios sprites que utilizan las mismas poses pueden calcular con este reloj qué pose les corresponde cada cuatro frames.&lt;br /&gt;
&lt;br /&gt;
Así todos cambian al mismo tiempo y solicitan la misma pose. La primera solicitud puede necesitar cargarla; las demás la reutilizan sin programar otra carga de sus gráficos. Esto ahorra transferencias DMA y datos enviados por frame.&lt;br /&gt;
&lt;br /&gt;
Si cada sprite llevara un reloj independiente, podrían terminar usando poses distintas de la misma animación al mismo tiempo y necesitar más cargas y espacio de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; se detiene durante la pausa y cuando se congela la acción, para que las animaciones sincronizadas también se detengan.&lt;br /&gt;
&lt;br /&gt;
== Carga de gráficos: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; guarda en RAM una lista de solicitudes de carga. Durante NMI se recorren esas solicitudes y se copian sus datos a VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Variables de la lista ===&lt;br /&gt;
&lt;br /&gt;
En esta tabla, &#039;&#039;&#039;V&#039;&#039;&#039; es el valor de &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt;: 64 por defecto. Las cuatro tablas de solicitudes reservan V bytes cada una; con entradas de 2 bytes, ese valor deja espacio para 32 solicitudes. Junto con el contador, reservan &amp;lt;code&amp;gt;1 + 4 × V&amp;lt;/code&amp;gt; bytes: 257 por defecto.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de solicitudes pendientes. El valor 0 indica que la lista está vacía.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Dirección de origen de cada solicitud, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 reservados; banco de 1 byte || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Cantidad de bytes que se copiarán.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Dirección de destino en VRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las tablas mantienen el mismo orden: la primera entrada de cada tabla pertenece a la primera solicitud, la segunda a la segunda, etc. Cada entrada de estas tablas ocupa 2 bytes, por lo que se avanza con desplazamientos de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt;, etc.&lt;br /&gt;
&lt;br /&gt;
Estos nombres representan direcciones de RAM calculadas en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus direcciones pueden cambiar según la configuración y las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
=== Añadir una solicitud ===&lt;br /&gt;
&lt;br /&gt;
La macro &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; realiza los siguientes pasos:&lt;br /&gt;
&lt;br /&gt;
# Calcula cuántos bytes habría en total al añadir la nueva carga a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Compara el resultado con &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;. Si lo supera, devuelve el carry desactivado y no añade la solicitud.&lt;br /&gt;
# Utiliza &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para encontrar la siguiente entrada y aumenta ese contador en 1.&lt;br /&gt;
# Guarda el origen, banco, cantidad de bytes y destino en las tablas.&lt;br /&gt;
# Actualiza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; con los bytes de la carga y devuelve el carry activado.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; guarda los mismos datos, pero no comprueba el límite de bytes. Las variantes &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; facilitan obtener el origen desde una dirección completa o desde los defines de un recurso.&lt;br /&gt;
&lt;br /&gt;
Añadir una solicitud no copia los gráficos inmediatamente: deja la información preparada para NMI.&lt;br /&gt;
&lt;br /&gt;
=== Ejecutar las solicitudes durante NMI ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Lee &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;. Si es 0, termina porque no hay solicitudes.&lt;br /&gt;
# Calcula el desplazamiento de la última entrada: &amp;lt;code&amp;gt;(Length - 1) × 2&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Lee su origen, banco y cantidad de bytes, y los coloca en los registros de DMA.&lt;br /&gt;
# Escribe el destino de VRAM en &amp;lt;code&amp;gt;$2116-$2117&amp;lt;/code&amp;gt; e inicia la transferencia mediante &amp;lt;code&amp;gt;$420B&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Retrocede 2 bytes para procesar la solicitud anterior. Repite hasta completar la primera.&lt;br /&gt;
# Escribe 0 en &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para indicar que la lista está vacía.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;La lista se ejecuta del final al inicio.&#039;&#039;&#039; No hace falta borrar todos sus datos al terminar: al quedar su largo en 0, la próxima solicitud volverá a utilizar la primera entrada.&lt;br /&gt;
&lt;br /&gt;
=== Animaciones con un destino fijo ===&lt;br /&gt;
&lt;br /&gt;
El código de una animación debe:&lt;br /&gt;
&lt;br /&gt;
# Elegir la imagen que corresponde al paso actual.&lt;br /&gt;
# Calcular su dirección de origen.&lt;br /&gt;
# Solicitar la copia al destino de VRAM de la animación.&lt;br /&gt;
# Comprobar el carry. Si se rechaza la carga, conservar la imagen anterior y volver a intentarlo.&lt;br /&gt;
&lt;br /&gt;
El destino puede ser siempre el mismo. Lo que cambia es la imagen que se copia allí; la lista de transferencias no decide cuándo debe avanzar la animación.&lt;br /&gt;
&lt;br /&gt;
Puedes ver un código completo en [[es/Dynamic_Xtreme_UberASM_guide#Crear_animaciones_de_gráficos|Crear animaciones de gráficos de la guía de UberASM]].&lt;br /&gt;
&lt;br /&gt;
=== Carga de una pose dinámica ===&lt;br /&gt;
&lt;br /&gt;
La carga de una pose utiliza la caché para no repetir transferencias de gráficos que ya están disponibles:&lt;br /&gt;
&lt;br /&gt;
# Busca el ID en la tabla hash.&lt;br /&gt;
# Si ya está registrado, actualiza su tiempo de uso y no añade otra carga.&lt;br /&gt;
# Si no está, comprueba la cantidad de bytes y busca un espacio adecuado en el mapa de VRAM.&lt;br /&gt;
# Elige qué poses pueden reemplazarse, teniendo en cuenta su tiempo sin uso y el espacio que necesita la nueva.&lt;br /&gt;
# Actualiza las tablas de la caché y el mapa.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; divide los datos de la pose en las transferencias necesarias.&lt;br /&gt;
# NMI ejecuta esas transferencias.&lt;br /&gt;
&lt;br /&gt;
Cada paso se desarrolla en [[#Sprites_dinámicos:_DynamicPoses|Sprites dinámicos: DynamicPoses]], incluyendo la búsqueda por hash, el mapa, la política de reemplazo y la división de la carga en filas.&lt;br /&gt;
&lt;br /&gt;
== Carga y asignación de paletas: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
El sistema distingue dos valores:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID de paleta:&#039;&#039;&#039; identifica los colores guardados en ROM.&lt;br /&gt;
* &#039;&#039;&#039;Color de destino:&#039;&#039;&#039; indica desde qué color de la paleta de colores de CGRAM se colocarán los colores que se carguen. Por ejemplo, &amp;lt;code&amp;gt;$91&amp;lt;/code&amp;gt; comienza en el color 1 de la paleta 9.&lt;br /&gt;
&lt;br /&gt;
La asignación automática permite compartir colores entre sprites sin exigir un destino fijo para cada uno.&lt;br /&gt;
&lt;br /&gt;
=== Lista de cargas a CGRAM ===&lt;br /&gt;
&lt;br /&gt;
En esta tabla, &#039;&#039;&#039;C&#039;&#039;&#039; es &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt;: 64 por defecto. El conjunto reserva &amp;lt;code&amp;gt;1 + 7 × C&amp;lt;/code&amp;gt; bytes, es decir, 449 con ese valor. Aunque &amp;lt;code&amp;gt;SourceBNK&amp;lt;/code&amp;gt; reserva 2 × C bytes, el código utiliza un byte de banco por solicitud.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Índice de la última solicitud pendiente. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; indica una lista vacía; 0 indica que hay una solicitud.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || 2 × C; 128 por defecto || 2 || Dirección de origen, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || 2 × C; 128 reservados por defecto || 1 utilizado por solicitud || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || 2 × C; 128 por defecto || 2 || Cantidad de bytes que se copiarán. Cada color ocupa 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || C; 64 por defecto || 1 || Primer color de destino en CGRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Durante NMI, &amp;lt;code&amp;gt;CGRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Comienza por la última solicitud pendiente.&lt;br /&gt;
# Configura DMA con el origen y la cantidad de bytes de esa solicitud.&lt;br /&gt;
# Selecciona el primer color mediante &amp;lt;code&amp;gt;$2121&amp;lt;/code&amp;gt; y realiza la copia.&lt;br /&gt;
# Continúa con las solicitudes anteriores.&lt;br /&gt;
# Al terminar, escribe &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; también actualizan las copias de colores y el estado de efectos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Sin efecto global:&#039;&#039;&#039; solicitan la carga y actualizan los buffers de SMW. Así el juego no vuelve a utilizar colores anteriores durante la animación de victoria del goal.&lt;br /&gt;
* &#039;&#039;&#039;Con efecto global:&#039;&#039;&#039; guardan los colores originales y preparan el estado necesario para aplicarles el efecto antes de enviarlos a CGRAM.&lt;br /&gt;
&lt;br /&gt;
=== Asignación automática ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 32 || 2 || Guarda el ID asignado a cada destino. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre y &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; una reservada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 16 || 1 || Protege cada destino del reemplazo automático mientras está en uso.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta de sprites || Indica qué paletas de sprites están asignadas con efecto global habilitado. Esta condición también se compara al compartir una asignación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue este orden:&lt;br /&gt;
&lt;br /&gt;
# Reutilizar una asignación con el mismo ID y una condición de efecto compatible.&lt;br /&gt;
# Si no existe, utilizar una entrada libre.&lt;br /&gt;
# Si no hay entradas libres, reemplazar una que no esté reservada y cuyo temporizador sea 0.&lt;br /&gt;
# Si no encuentra ninguna, indicar que la asignación falló.&lt;br /&gt;
&lt;br /&gt;
Mientras el recurso utiliza la paleta, mantiene su temporizador en 2. Llegar a 0 no borra los colores: la asignación puede reutilizarse si otro recurso todavía no la reemplazó.&lt;br /&gt;
&lt;br /&gt;
=== Asignación manual y versión ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Manual con carga:&#039;&#039;&#039; el código elige el destino y solicita sus colores.&lt;br /&gt;
* &#039;&#039;&#039;Manual sin carga:&#039;&#039;&#039; el código elige el destino y utiliza los colores que ya estaban preparados.&lt;br /&gt;
* &#039;&#039;&#039;Versión:&#039;&#039;&#039; selecciona una entrada de la lista de paletas del DynamicInfo. La última versión procesada permite comprobar si esa selección cambió.&lt;br /&gt;
&lt;br /&gt;
Dos recursos que elijan el mismo destino con colores distintos deben coordinarse. Mantener la protección de una paleta no significa volver a cargar sus colores.&lt;br /&gt;
&lt;br /&gt;
== Dibujo de poses: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
El dibujo prepara las piezas de una pose en OAM: qué tiles se muestran, dónde se colocan y qué propiedades utilizan. Los datos gráficos deben estar en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Pasos del dibujo ===&lt;br /&gt;
&lt;br /&gt;
# Busca la rutina y los datos de la pose mediante &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Obtiene la cantidad de piezas desde &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Calcula la posición de cada tile usando la posición del sprite, sus desplazamientos y los volteos que correspondan.&lt;br /&gt;
# Comprueba si la pieza puede verse y si queda espacio de OAM.&lt;br /&gt;
# Escribe su posición, número de tile, propiedades y tamaño en los buffers OAM.&lt;br /&gt;
&lt;br /&gt;
El número de tile depende del dibujo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Cómo se obtiene el tile&lt;br /&gt;
|-&lt;br /&gt;
| Pose dinámica || Se ajusta al lugar de VRAM donde quedaron cargados sus gráficos.&lt;br /&gt;
|-&lt;br /&gt;
| Pose estática || Se utiliza su número de tile fijo.&lt;br /&gt;
|-&lt;br /&gt;
| Pose que utiliza un tile común || El código debe preparar &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; antes de llamar al dibujo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Prioridad y espacio disponible ===&lt;br /&gt;
&lt;br /&gt;
* En &#039;&#039;&#039;LoROM&#039;&#039;&#039;, el sistema lleva su propio control de entradas OAM disponibles.&lt;br /&gt;
* En &#039;&#039;&#039;SA-1&#039;&#039;&#039;, utiliza la integración con MaxTile.&lt;br /&gt;
* La &#039;&#039;&#039;prioridad de dibujo&#039;&#039;&#039; organiza las piezas de sprites. No es la misma propiedad que determina si un tile queda delante o detrás de las capas.&lt;br /&gt;
* Los &#039;&#039;&#039;límites por línea de pantalla&#039;&#039;&#039; de SNES siguen existiendo. Tener una pose cargada no garantiza que puedan verse todas sus piezas.&lt;br /&gt;
&lt;br /&gt;
== Jugador y Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
El jugador original tiene rutinas propias para elegir y cargar las piezas de sus poses. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; permite integrar ese trabajo con las cargas de Dynamic Xtreme y cambiar el origen de sus gráficos y paletas.&lt;br /&gt;
&lt;br /&gt;
Con el formato original, el juego sigue eligiendo las piezas de la pose. La rutina obtiene sus direcciones desde el origen configurado y compara esas direcciones con las anteriores para cargar las que hayan cambiado.&lt;br /&gt;
&lt;br /&gt;
Estas cargas utilizan transferencias forzadas y sus bytes también cuentan para las solicitudes normales posteriores. Así conservan su prioridad sin quedar fuera de la contabilidad del sistema.&lt;br /&gt;
&lt;br /&gt;
La paleta del jugador tiene un tratamiento especial: combina colores y selecciones del propio juego con el origen personalizado. No funciona simplemente como sustituir una paleta completa de un sprite cualquiera.&lt;br /&gt;
&lt;br /&gt;
El soporte para jugadores personalizados permite que otros sistemas administren de otra forma sus poses y dibujo. No convierte automáticamente cualquier spritesheet al formato del jugador original.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi también carga sus gráficos por piezas. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; permite cambiar su origen manteniendo la organización que esperan sus rutinas.&lt;br /&gt;
&lt;br /&gt;
El código calcula qué partes necesita y prepara sus cargas a los destinos correspondientes de VRAM. Como las del jugador, estas cargas tienen un tratamiento prioritario.&lt;br /&gt;
&lt;br /&gt;
Esta opción necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad. No permite evitar un conflicto del sistema del jugador habilitando únicamente las funciones de Yoshi.&lt;br /&gt;
&lt;br /&gt;
== Memoria y optimizaciones ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW mantiene en RAM gráficos originales del jugador, Yoshi y ciertas animaciones. En ROMs sin SA-1, esta opción adapta las cargas para leer esos datos desde ROM.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aprovecha la RAM recuperada para sus variables internas. No es un espacio que quede libre para que cualquier otro código escriba encima.&lt;br /&gt;
&lt;br /&gt;
SA-1 utiliza otras direcciones y desactiva esta opción. Los rangos están en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
Esta opción mueve el procesamiento del control desde NMI a la parte de game mode. El objetivo es dejar más tiempo para las actualizaciones de pantalla, no añadir un frame de retraso ni cambiar los botones que recibe el juego.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
El color fijo se utiliza en las mezclas de color de la consola. Para actualizarlo, el juego prepara sus componentes y los envía al registro correspondiente.&lt;br /&gt;
&lt;br /&gt;
La optimización reemplaza esa preparación por una secuencia más corta. El color sigue enviándose a la consola, pero necesita menos trabajo durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic utiliza listas llamadas stripe images para actualizar partes de los mapas de tiles. Esas listas incluyen tanto los datos como la información sobre sus destinos.&lt;br /&gt;
&lt;br /&gt;
La versión integrada de la optimización de Kevin prepara fuera de NMI parte del ajuste de esos destinos. Así deja menos trabajo de preparación para el momento de la transferencia.&lt;br /&gt;
&lt;br /&gt;
Esta opción sustituye el uso del parche original por separado. Además, no debe desinstalarse después de instalarla; hay que tenerlo en cuenta antes de activarla.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
La barra de estado original actualiza zonas concretas de VRAM. Esta opción prepara sus transferencias de forma más directa, reduciendo la configuración de DMA que necesita hacer durante NMI.&lt;br /&gt;
&lt;br /&gt;
No añade una barra nueva. Modifica la actualización de la original y, por eso, entra en conflicto con recursos que la reemplazan, modifican o eliminan.&lt;br /&gt;
&lt;br /&gt;
== Sprites dinámicos: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
El sistema funciona como una &#039;&#039;&#039;caché de poses en VRAM&#039;&#039;&#039;. No reserva una copia de los gráficos para cada sprite: guarda la pose y permite que la reutilicen todos los recursos que la necesiten.&lt;br /&gt;
&lt;br /&gt;
* Una pose se carga una sola vez mientras permanezca en la caché.&lt;br /&gt;
* Las siguientes solicitudes actualizan su tiempo de último uso, sin añadir otra carga de sus gráficos.&lt;br /&gt;
* La pose no se borra cuando un recurso deja de utilizarla. Permanece allí hasta que se necesite su espacio y se elija reemplazarla.&lt;br /&gt;
* Si fue reemplazada y vuelve a solicitarse, tendrá que cargarse otra vez.&lt;br /&gt;
&lt;br /&gt;
La elección no depende de cuánto tiempo lleva la pose desde que se cargó, sino de &#039;&#039;&#039;cuánto tiempo lleva sin utilizarse&#039;&#039;&#039; y de si su espacio sirve para la pose nueva.&lt;br /&gt;
&lt;br /&gt;
=== Tres valores distintos ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Qué identifica&lt;br /&gt;
|-&lt;br /&gt;
| ID de pose || La pose instalada. Tiene 16 bits y permite consultar sus datos en ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Índice de la tabla hash || La entrada de RAM donde se registró la pose. Va de 0 a 127.&lt;br /&gt;
|-&lt;br /&gt;
| Bloque de VRAM || ID de una de las 128 posiciones para tiles de 16×16 que caben en el espacio de VRAM de sprites. Se numeran de izquierda a derecha y de arriba abajo, desde 0 hasta 127. Para una pose que ocupa varios bloques, se guarda el ID de su primer bloque.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
El índice de la tabla hash y el bloque de VRAM no tienen por qué coincidir. Una entrada de la tabla puede registrar una pose que empieza en cualquier bloque permitido.&lt;br /&gt;
&lt;br /&gt;
=== Tablas de las poses registradas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de poses registradas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 || 1 || Cantidad de poses registradas para cada hash.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 256 || 2 || ID completo de la pose de cada entrada. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Bloque de VRAM donde comienza cada pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 256 || 2 || Valor de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; de su último uso.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas ocupan &#039;&#039;&#039;769 bytes&#039;&#039;&#039; en RAM. Guardan las poses registradas durante el juego; las tablas generadas desde el DynamicInfo describen, en cambio, todas las poses instaladas.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se busca una pose ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;DynamicPoseHashmap_FindPose&amp;lt;/code&amp;gt; utiliza una tabla hash de 128 entradas. El hash permite elegir dónde empezar a buscar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hash = ID de pose AND $007F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dos IDs diferentes pueden tener el mismo hash. Por ejemplo, &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; producen &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;. Por eso el hash no basta para confirmar que la pose está cargada: también se compara el ID completo.&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue estos pasos:&lt;br /&gt;
&lt;br /&gt;
# Guarda el ID solicitado y calcula su hash.&lt;br /&gt;
# Si &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; es 0, no hay poses registradas y la búsqueda termina.&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize[hash]&amp;lt;/code&amp;gt;. Si es 0, ninguna pose registrada tiene ese hash y también termina.&lt;br /&gt;
# Comienza por la entrada cuyo índice coincide con el hash.&lt;br /&gt;
# Lee el ID de esa entrada. Si coincide con el solicitado, encontró la pose.&lt;br /&gt;
# Si no coincide, continúa con la siguiente entrada de la secuencia de búsqueda.&lt;br /&gt;
&lt;br /&gt;
La secuencia avanza &#039;&#039;&#039;15 entradas por intento&#039;&#039;&#039; y vuelve al comienzo al superar 127:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
siguiente índice = (índice actual + 15) AND $7F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Con 128 entradas, ese paso permite visitar todas las posiciones antes de repetir una. Para el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, el comienzo de la secuencia es:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$05 → $14 → $23 → $32 → $41 → ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== El contador de poses de cada hash ====&lt;br /&gt;
&lt;br /&gt;
Cada hash tiene su propio contador en &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt;. Por ejemplo, si hay dos poses registradas cuyo ID produce el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, la entrada &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize+$05&amp;lt;/code&amp;gt; contiene 2.&lt;br /&gt;
&lt;br /&gt;
Ese número indica &#039;&#039;&#039;cuántas poses con ese hash existen&#039;&#039;&#039;, no cuántas posiciones hay que recorrer. La búsqueda utiliza una copia temporal del contador:&lt;br /&gt;
&lt;br /&gt;
# Comienza con la cantidad de poses registrada para el hash solicitado.&lt;br /&gt;
# Recorre las posiciones de la secuencia hasta encontrar el ID solicitado o haber comprobado esa cantidad de poses con el mismo hash.&lt;br /&gt;
# Cada vez que encuentra una pose con ese hash, pero con otro ID, resta 1 al contador temporal.&lt;br /&gt;
# Las posiciones libres y las poses de otros hashes no descuentan nada: continúa buscando.&lt;br /&gt;
# Si el contador temporal llega a 0 sin encontrar el ID, la pose solicitada no está registrada y la búsqueda termina.&lt;br /&gt;
&lt;br /&gt;
El contador de &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; no se modifica durante esta búsqueda. Solo se actualiza al añadir o retirar poses de la caché.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, se busca &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt;, que produce el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, y el contador de ese hash vale 2:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Posición visitada !! ID guardado !! Hash del ID !! Poses del hash $05 que faltan por comprobar&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 1: tiene el mismo hash, pero no es el ID solicitado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0014&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || 1: es otro hash, así que no se descuenta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$23&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 0: ya se comprobaron las dos poses con ese hash. &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt; no está registrada.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Lo habitual es que haya una o dos poses por hash. Esto permite resolver la búsqueda con pocas comprobaciones y un coste normalmente cercano a &amp;lt;code&amp;gt;O(1)&amp;lt;/code&amp;gt;. No significa que siempre se visiten solo una o dos posiciones: puede haber entradas de otros hashes entre ellas. Con muchas colisiones, el recorrido puede ser más largo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Una entrada libre no termina la búsqueda.&#039;&#039;&#039; Puede haber quedado vacía al reemplazar una pose y existir otra del mismo hash más adelante. El contador permite saber cuándo ya se comprobaron todas las poses de ese hash, incluso si hay huecos entre ellas.&lt;br /&gt;
&lt;br /&gt;
==== Cuando encuentra la pose ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Obtiene el índice de la entrada encontrada.&lt;br /&gt;
# Escribe el valor actual de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; para esa entrada.&lt;br /&gt;
# Devuelve el éxito de la solicitud, sin volver a programar la carga de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
Así todos los recursos que solicitan ese ID utilizan la misma pose y la mantienen protegida. No importa si el recurso es un sprite normal, cluster, extended u otro código que utiliza el sistema.&lt;br /&gt;
&lt;br /&gt;
Esto también evita duplicar una carga dentro del mismo ciclo: cuando la primera solicitud se acepta, la pose ya queda registrada aunque la transferencia física se vaya a realizar durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== Cuando la pose no está registrada ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt; continúa con la preparación de una carga nueva:&lt;br /&gt;
&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; y calcula &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend + PoseSize&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, termina con fallo, sin cambiar las poses existentes.&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; para saber cuántos bloques necesita.&lt;br /&gt;
# Llama a &amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; para buscar un espacio adecuado.&lt;br /&gt;
# Si no existe un espacio utilizable, termina con fallo.&lt;br /&gt;
# Retira del mapa y de la tabla hash las poses que ocupen el espacio elegido.&lt;br /&gt;
# Busca una entrada libre de la tabla hash y registra la pose nueva.&lt;br /&gt;
# Actualiza el mapa de VRAM y el contador de datos del frame.&lt;br /&gt;
# Llama a &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; para añadir las transferencias.&lt;br /&gt;
&lt;br /&gt;
El presupuesto se comprueba antes de reemplazar poses. Si la nueva carga no cabe en el frame, no se libera espacio para una solicitud que no se puede atender.&lt;br /&gt;
&lt;br /&gt;
==== Añadir y quitar entradas de la tabla hash ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_FindFreeSpace&amp;lt;/code&amp;gt; busca una entrada cuyo ID sea &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt;, siguiendo la misma secuencia de pasos de 15.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; guarda el ID y su tiempo de uso, aumenta &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; y aumenta el contador de su hash.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Remove&amp;lt;/code&amp;gt; escribe &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; en el ID retirado y reduce ambos contadores.&lt;br /&gt;
&lt;br /&gt;
Retirar una entrada no borra por sí solo los píxeles de VRAM. Indica que esa pose dejó de estar disponible en la caché; las nuevas transferencias sobrescribirán el espacio elegido.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se representa el mapa de VRAM ===&lt;br /&gt;
&lt;br /&gt;
El mapa representa &#039;&#039;&#039;128 posiciones de tiles de 16×16 en la VRAM de sprites&#039;&#039;&#039;, numeradas de izquierda a derecha y de arriba abajo. Cada bloque es una de esas posiciones, no un tramo de 128 bytes contiguos.&lt;br /&gt;
&lt;br /&gt;
Un tile de 16×16 está formado por cuatro tiles de 8×8 distribuidos en dos filas. El mapa administra las posiciones que ocupa la pose; la distribución de sus datos para cargarlos se resuelve después en &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Posición donde comienza la sección. El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica que está restringida: ese espacio no se utiliza para poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt;, también llamada &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 || 1 || Si el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; está activo, los otros bits guardan la cantidad de posiciones de la sección menos uno. Si está desactivado, guardan el índice hash de la pose que ocupa la sección. Para saber si el espacio está restringido, se consulta &amp;lt;code&amp;gt;Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas dos tablas ocupan &#039;&#039;&#039;256 bytes&#039;&#039;&#039;. Junto con las tablas de poses, el administrador utiliza &#039;&#039;&#039;1025 bytes&#039;&#039;&#039; de RAM, sin contar las listas de transferencias ni las scratch de trabajo.&lt;br /&gt;
&lt;br /&gt;
=== Secciones del mapa ===&lt;br /&gt;
&lt;br /&gt;
Una sección agrupa posiciones consecutivas del mapa que están restringidas, libres o utilizadas por una pose. Su información se guarda en &#039;&#039;&#039;la primera y la última posición&#039;&#039;&#039;. Esto permite saltar de una sección a la anterior sin revisar todas sus posiciones intermedias.&lt;br /&gt;
&lt;br /&gt;
Los siguientes ejemplos muestran tres estados posibles para una sección de 6 posiciones, de &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;. Son casos alternativos, no tres secciones que ocupen el mismo espacio a la vez.&lt;br /&gt;
&lt;br /&gt;
==== Ejemplo 1: sección restringida ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Entradas de las tablas !! Valor !! Significado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$A0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica restringida y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; indica dónde comienza.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$85&amp;lt;/code&amp;gt; || La sección tiene 6 posiciones: &amp;lt;code&amp;gt;($85 AND $7F) + 1 = 6&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Aunque el bit alto de &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt; esté activo, &#039;&#039;&#039;no es espacio libre para poses dinámicas&#039;&#039;&#039;: el bit de restricción en &amp;lt;code&amp;gt;Offset&amp;lt;/code&amp;gt; hace que se descarte. No se evalúa como una pose que pueda reemplazarse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; utiliza este tipo de sección para excluir las partes de SP1-SP4 que no deben utilizar los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
==== Ejemplo 2: sección libre ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Entradas de las tablas !! Valor !! Significado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || Comienza en &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; y no está restringida.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$85&amp;lt;/code&amp;gt; || El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica el tamaño de una sección libre: &amp;lt;code&amp;gt;$05 + 1 = 6&amp;lt;/code&amp;gt; posiciones.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Esta sección sí está disponible. Puede alojar una pose que necesite hasta 6 posiciones; si se coloca una de 4, las otras 2 quedan como otra sección libre.&lt;br /&gt;
&lt;br /&gt;
==== Ejemplo 3: sección utilizada por una pose ====&lt;br /&gt;
&lt;br /&gt;
Supongamos que una pose de 6 bloques está registrada en la entrada hash &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; y ocupa las posiciones &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Entradas de las tablas !! Valor !! Significado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || La sección comienza en &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; y no está restringida.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; está desactivado: &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; es el índice hash de la pose, no su cantidad de bloques.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para conocer la cantidad de posiciones y el tiempo sin uso:&lt;br /&gt;
&lt;br /&gt;
# Se lee el ID de la pose en &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID+$0E&amp;lt;/code&amp;gt;. Se utiliza &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; porque cada ID ocupa 2 bytes y &amp;lt;code&amp;gt;$07 × 2 = $0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Con ese ID se consulta &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt;, que en este ejemplo contiene 6.&lt;br /&gt;
# Se consulta &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse+$0E&amp;lt;/code&amp;gt; para calcular cuánto lleva sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
La entrada &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset+$07&amp;lt;/code&amp;gt; guarda &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;, relacionando esa pose registrada con su posición en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Recorrido y búsqueda de espacio ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; comienza por la posición de tile de 16×16 &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt;. Para recorrer el mapa:&lt;br /&gt;
&lt;br /&gt;
# Lee &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; de la posición actual.&lt;br /&gt;
# Obtiene el comienzo de la sección con &amp;lt;code&amp;gt;Offset AND $7F&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Evalúa esa sección y los espacios que pueda formar con otras secciones contiguas.&lt;br /&gt;
# Pasa a la posición &amp;lt;code&amp;gt;comienzo de la sección - 1&amp;lt;/code&amp;gt;, que es la última posición de la sección anterior.&lt;br /&gt;
# Repite hasta llegar al comienzo del mapa.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si las últimas secciones comienzan en &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Posición visitada !! Comienzo leído de Offset !! Próxima posición&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4F&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Así recorre &#039;&#039;&#039;secciones completas&#039;&#039;&#039;, no cada tile intermedio.&lt;br /&gt;
&lt;br /&gt;
==== Qué se evalúa durante el recorrido ====&lt;br /&gt;
&lt;br /&gt;
El espacio candidato puede ser &#039;&#039;&#039;una sección o varias secciones contiguas&#039;&#039;&#039;. En cada paso se comprueba:&lt;br /&gt;
&lt;br /&gt;
* Si hay una sección restringida, no se utiliza ni se combina a través de ella.&lt;br /&gt;
* Si hay una pose protegida por su uso reciente, tampoco puede formar parte del espacio.&lt;br /&gt;
* Si el candidato todavía es pequeño, se puede continuar con una sección contigua para completar la cantidad de bloques necesaria.&lt;br /&gt;
* Si ya cabe la pose, se compara el candidato con el mejor encontrado: primero por su score de tiempo sin uso y después por el espacio suficiente más pequeño.&lt;br /&gt;
&lt;br /&gt;
No se elige una sección solo por contener la pose con más tiempo sin uso. El &#039;&#039;&#039;espacio completo&#039;&#039;&#039; debe permitir cargar la pose nueva. La puntuación de varias secciones combinadas depende de la pose utilizada más recientemente dentro de ese espacio.&lt;br /&gt;
&lt;br /&gt;
Durante la búsqueda se conservan estos datos temporales:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos de trabajo !! Bytes totales !! Bytes por valor !! Para qué se usan&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapCurrentSpace&amp;lt;/code&amp;gt; || 3 || 1 por campo || Comienzo, score y cantidad de bloques del espacio candidato actual.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapBestSpace&amp;lt;/code&amp;gt; || 3 || 1 por campo || Los mismos campos para el mejor espacio encontrado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapTMP_Size&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de bloques que necesita la pose nueva.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos nombres utilizan scratch de trabajo, no RAM persistente adicional.&lt;br /&gt;
&lt;br /&gt;
=== Política de reemplazo: tiempo sin uso y espacio suficiente ===&lt;br /&gt;
&lt;br /&gt;
El sistema no elige simplemente la pose que se cargó primero. Utiliza el tiempo transcurrido desde su &#039;&#039;&#039;último uso&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tiempo sin uso = DX_Timer - TimeLastUse de la pose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMapSlot_GetSizeAndScore&amp;lt;/code&amp;gt; obtiene el tamaño y una puntuación para cada región:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Puntuación y tratamiento&lt;br /&gt;
|-&lt;br /&gt;
| Región libre || &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Se favorece frente a regiones ocupadas.&lt;br /&gt;
|-&lt;br /&gt;
| Región ocupada || Tiempo sin uso, limitado a &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Tiempo sin uso de 0 o 1 || No se puede reemplazar: la pose sigue protegida.&lt;br /&gt;
|-&lt;br /&gt;
| Región restringida || Se descarta: ese espacio no se utiliza para poses dinámicas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La protección exige &#039;&#039;&#039;al menos dos avances de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; sin utilizar la pose&#039;&#039;&#039;. Cada recurso que vuelve a solicitarla actualiza su tiempo de uso y vuelve a protegerla.&lt;br /&gt;
&lt;br /&gt;
==== Por qué no siempre se reemplaza la pose con más tiempo sin uso ====&lt;br /&gt;
&lt;br /&gt;
La pose nueva necesita espacio suficiente y contiguo. Un espacio pequeño no sirve por sí solo, aunque lleve mucho tiempo sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para una pose nueva de 4 bloques:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Espacio candidato !! Tiempo sin uso !! ¿Sirve?&lt;br /&gt;
|-&lt;br /&gt;
| Pose A: 2 bloques, sin espacio contiguo utilizable || 20 || No: solo deja 2 bloques.&lt;br /&gt;
|-&lt;br /&gt;
| Pose B: 4 bloques || 8 || Sí: puede alojar la pose nueva.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
En este caso se puede reemplazar B y conservar A. A lleva más tiempo sin uso, pero su espacio no permite atender la solicitud.&lt;br /&gt;
&lt;br /&gt;
Si dos o más regiones contiguas pueden reemplazarse, el sistema puede considerarlas juntas. Para esa combinación:&lt;br /&gt;
&lt;br /&gt;
* Suma sus cantidades de bloques.&lt;br /&gt;
* Utiliza la &#039;&#039;&#039;menor puntuación&#039;&#039;&#039; de las regiones combinadas, es decir, el menor tiempo sin uso.&lt;br /&gt;
* Si una está restringida o protegida, no puede utilizarla para completar el espacio.&lt;br /&gt;
&lt;br /&gt;
Así una pose usada recientemente no puede quedar sobrescrita por combinarla con otra que lleva mucho tiempo sin uso.&lt;br /&gt;
&lt;br /&gt;
==== Elegir entre candidatos válidos ====&lt;br /&gt;
&lt;br /&gt;
# El candidato debe tener al menos la cantidad de bloques solicitada.&lt;br /&gt;
# Se prefiere la puntuación más alta: espacio libre o mayor tiempo sin uso.&lt;br /&gt;
# Si las puntuaciones son iguales, se prefiere el candidato con menos bloques, siempre que la pose quepa.&lt;br /&gt;
# Si puntuación y tamaño también coinciden, se conserva el candidato que ya se había elegido.&lt;br /&gt;
&lt;br /&gt;
Las regiones se combinan durante la búsqueda cuando el candidato todavía es demasiado pequeño. No se juntan todas las regiones reemplazables sin tener en cuenta el tamaño solicitado.&lt;br /&gt;
&lt;br /&gt;
=== Reemplazar y dividir la región elegida ===&lt;br /&gt;
&lt;br /&gt;
Una vez elegido el espacio:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemovePosesInSpace&amp;lt;/code&amp;gt; recorre sus regiones y retira de la tabla hash las poses que haya que reemplazar.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemoveSpace&amp;lt;/code&amp;gt; representa el espacio elegido como una región libre, actualizando sus extremos.&lt;br /&gt;
# Se busca una entrada hash libre y se guarda el bloque de comienzo en &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; registra la pose.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_AddPoseInSpace&amp;lt;/code&amp;gt; escribe el índice hash de la pose y el comienzo de su región en el primer y último bloque.&lt;br /&gt;
# Si sobran bloques, crea otra región libre con el resto.&lt;br /&gt;
&lt;br /&gt;
Si una región de 6 bloques aloja una pose de 4, quedan una región ocupada de 4 y una libre de 2. No se mueven las demás poses para compactar VRAM.&lt;br /&gt;
&lt;br /&gt;
=== DynamicRoutine: preparar las transferencias de la pose ===&lt;br /&gt;
&lt;br /&gt;
En este punto ya se eligió el espacio y se registró la pose. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; convierte esa asignación en solicitudes de transferencia.&lt;br /&gt;
&lt;br /&gt;
Utiliza estos datos:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Dato !! Cantidad consultada por pose !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Bloque de comienzo || 1 byte || Lugar elegido por el mapa de VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; || 2 bytes de una tabla de 256 bytes || Convierte uno de los 128 bloques en un desplazamiento de VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 bytes || Dirección completa de los datos de la pose en ROM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 bytes: dos valores de 2 || Cantidad de bytes del primer y del segundo tramo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 bytes || Desplazamiento de VRAM para el segundo tramo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Convertir el bloque en una dirección de VRAM ====&lt;br /&gt;
&lt;br /&gt;
Los bloques de 16×16 no se convierten simplemente en un desplazamiento lineal de bytes. Cada uno utiliza tiles de 8×8 distribuidos en las filas de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; contempla esa distribución. Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bloque !! Desplazamiento !! Dirección de VRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas direcciones de VRAM están expresadas en palabras de 2 bytes, no en bytes. La rutina suma la base &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; utilizada para los gráficos de sprites.&lt;br /&gt;
&lt;br /&gt;
==== Procesar los tramos y sus filas ====&lt;br /&gt;
&lt;br /&gt;
# Obtiene el origen desde &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Procesa los bytes del primer tramo mediante &amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si el segundo tramo tiene tamaño 0, termina.&lt;br /&gt;
# Si existe, adelanta el origen la cantidad de bytes del primer tramo.&lt;br /&gt;
# Suma &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; al desplazamiento de VRAM y procesa el segundo tramo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt; divide cada tramo según las filas y el punto de comienzo. Para un destino V expresado en palabras de VRAM, prepara:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Final de la primera fila = (V + $0100) AND $FF00&lt;br /&gt;
Bytes hasta ese final = (final de la primera fila - V) × 2&lt;br /&gt;
Destino de la segunda parte = final de la primera fila + $0100&lt;br /&gt;
Bytes de la segunda parte de un grupo = $0200 - bytes de la primera&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los tamaños son cantidades de bytes, mientras que los destinos de VRAM están expresados en palabras. Por eso se multiplica por 2 al calcular cuántos datos caben hasta el final de una fila.&lt;br /&gt;
&lt;br /&gt;
La rutina utiliza tres recorridos:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt;: añade una solicitud final con los bytes restantes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLinesWithEndLine&amp;lt;/code&amp;gt;: añade dos solicitudes para los datos restantes, cada una con su destino y cantidad de bytes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLines&amp;lt;/code&amp;gt;: añade dos solicitudes que suman &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, avanza el origen y los destinos y repite con los datos que faltan.&lt;br /&gt;
&lt;br /&gt;
Hay un caso directo antes del recorrido general: si el destino comienza en un límite de &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; palabras y el tramo tiene al menos &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, la rutina utiliza &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt; para preparar la copia del tramo completo en una solicitud.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, un tramo de &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes que comienza en &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; se divide así:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Solicitud !! Origen !! Destino VRAM !! Bytes&lt;br /&gt;
|-&lt;br /&gt;
| Primera || Comienzo del tramo || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt;: 448&lt;br /&gt;
|-&lt;br /&gt;
| Segunda || Comienzo del tramo + &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0040&amp;lt;/code&amp;gt;: 64&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las dos solicitudes copian los 512 bytes del tramo, respetando los destinos que calcula la distribución de filas. No son dos copias completas de la pose.&lt;br /&gt;
&lt;br /&gt;
Cada solicitud utiliza estas tablas:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Por cada solicitud añadida aumenta &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
La cantidad total de bytes de la pose ya se comprobó y se añadió a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;. Esta parte divide esa carga en transferencias; no vuelve a contar la pose completa por cada solicitud.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; &#039;&#039;&#039;no ejecuta DMA&#039;&#039;&#039;. Deja las solicitudes preparadas para que &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt; las copie durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== Qué conserva el sprite ===&lt;br /&gt;
&lt;br /&gt;
Las rutinas de sprites guardan el índice hash de la pose utilizable, no una copia independiente de sus gráficos. Ese índice permite consultar su bloque de VRAM y mantener actualizado su tiempo de uso.&lt;br /&gt;
&lt;br /&gt;
Si una pose nueva no puede cargarse:&lt;br /&gt;
&lt;br /&gt;
* Si existe una pose anterior válida, se mantiene y se actualiza su tiempo de uso para protegerla.&lt;br /&gt;
* Si nunca hubo una pose válida, no se debe dibujar como si la solicitud hubiera tenido éxito.&lt;br /&gt;
* En las llamadas con soporte para mantener la anterior, el carry puede indicar que todavía hay una pose utilizable aunque no se haya completado el cambio.&lt;br /&gt;
&lt;br /&gt;
La animación y el movimiento siguen siendo responsabilidad del sprite. La caché se ocupa de reutilizar o preparar los gráficos solicitados.&lt;br /&gt;
&lt;br /&gt;
=== Ejemplo: dos sprites solicitan la misma pose ===&lt;br /&gt;
&lt;br /&gt;
Supongamos que dos sprites visibles, A y B, necesitan la pose dinámica &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt;. Sus paletas ya están listas, la pose todavía no está en VRAM y hay espacio y presupuesto para cargarla.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;El sprite A solicita la pose.&#039;&#039;&#039; La búsqueda no encuentra &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; en la caché. El sistema elige un espacio, registra la pose y prepara las transferencias de sus gráficos. A guarda el índice de esa entrada en &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;. Los gráficos aún no se han copiado a VRAM.&lt;br /&gt;
# &#039;&#039;&#039;A prepara su dibujo.&#039;&#039;&#039; La rutina de dibujo utiliza la entrada registrada para calcular los tiles que corresponden a ese espacio de VRAM y escribe sus posiciones y propiedades en los buffers OAM.&lt;br /&gt;
# &#039;&#039;&#039;El sprite B solicita la misma pose.&#039;&#039;&#039; La búsqueda ya encuentra &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; registrada, aunque su transferencia siga pendiente. Actualiza su tiempo de último uso y no programa otra carga. B guarda el mismo índice de caché en su propia &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &#039;&#039;&#039;B prepara su dibujo.&#039;&#039;&#039; Escribe sus propias piezas en los buffers OAM, utilizando los mismos gráficos que A, pero con su posición, paleta y volteo.&lt;br /&gt;
# &#039;&#039;&#039;Durante NMI se actualizan los datos de video.&#039;&#039;&#039; Se realizan las transferencias pendientes de la pose a VRAM y el juego transfiere los buffers OAM. En la siguiente imagen, los dos sprites utilizan los mismos gráficos cargados.&lt;br /&gt;
&lt;br /&gt;
Se prepara una sola carga de la pose, aunque dos sprites la utilicen. Esa carga puede necesitar varias transferencias DMA según cómo se distribuyan sus gráficos en VRAM.&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, que la pose esté &#039;&#039;&#039;disponible&#039;&#039;&#039; durante la lógica significa que ya tiene una entrada y un espacio asignados, con su carga preparada para NMI. Si sus gráficos ya estaban en VRAM, se reutilizan directamente y no hay que preparar otra transferencia.&lt;br /&gt;
&lt;br /&gt;
Si la solicitud de A fuera rechazada, no se registraría la pose nueva ni quedaría su carga pendiente. A utilizaría su pose anterior si tiene una; de lo contrario, no dispondría de una pose para dibujar. B tendría que resolver su propia solicitud y no encontraría una entrada creada por el intento rechazado de A.&lt;br /&gt;
&lt;br /&gt;
== Efectos de paleta: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
El sistema conserva los colores originales para poder cambiar de efecto, combinarlo con otro o volver a la paleta sin efecto. No debe utilizar el resultado ya afectado como si fuera la paleta original.&lt;br /&gt;
&lt;br /&gt;
=== Buffers de colores ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o buffer !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 || 2 por color || Colores de base en formato SNES, con 2 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 || 3 por color || Base separada en rojo, verde y azul, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 || 3 por color || Base separada en tono, saturación y luminosidad, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 || 2 por color || Resultado en formato SNES, listo para solicitar su copia a CGRAM. Corresponde al buffer de paletas del juego.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Indicadores de cada paleta ===&lt;br /&gt;
&lt;br /&gt;
Cada bit de estos indicadores corresponde a una paleta. Las variables &amp;lt;code&amp;gt;BG&amp;lt;/code&amp;gt; cubren 0-7 y las &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt; cubren 8-F.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variables !! Bytes totales !! Bytes por valor !! Qué indican&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si ya se preparó la base de colores en formato SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparada la conversión de la base a RGB.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparada la conversión de la base a HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparado el resultado del efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos indicadores evitan repetir conversiones y cálculos que siguen siendo válidos.&lt;br /&gt;
&lt;br /&gt;
=== Preparar una base ===&lt;br /&gt;
&lt;br /&gt;
# Se comprueba si la paleta ya tiene una base registrada.&lt;br /&gt;
# Si no la tiene, se obtienen los colores del buffer del juego. Una carga explícita, como &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, puede proporcionar esa base directamente.&lt;br /&gt;
# Se comprueba si el efecto necesita RGB o HSL.&lt;br /&gt;
# Si falta esa conversión, se prepara y se marca como disponible.&lt;br /&gt;
&lt;br /&gt;
Si solo cambia el efecto, la base puede seguir siendo válida. Si cambian los colores originales, las llamadas de carga actualizan la base e invalidan las conversiones y resultados que deben calcularse otra vez.&lt;br /&gt;
&lt;br /&gt;
=== Datos de un efecto ===&lt;br /&gt;
&lt;br /&gt;
El ID permite consultar las tablas generadas durante la instalación:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt;: cálculo que debe realizarse.&lt;br /&gt;
* &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt;: valores de los canales o dirección de la paleta de destino de una transición.&lt;br /&gt;
* &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt;: cuánto se aplica cada cambio.&lt;br /&gt;
&lt;br /&gt;
Los canales utilizan valores de 0 a 31. Los ratios van de 0 a 127: 0 conserva el origen y 127 aplica por completo el cambio elegido.&lt;br /&gt;
&lt;br /&gt;
Los cálculos se realizan fuera de NMI. NMI realiza la transferencia de los colores resultantes.&lt;br /&gt;
&lt;br /&gt;
=== Efecto global ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Bytes totales !! Bytes por valor !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 || 2 || Selecciona el efecto global. El valor 0 permite restaurar los colores de base.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta || Selecciona las paletas 0-7 que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta || Selecciona las paletas 8-F que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 32 || 2 || Guarda el último ID global procesado por cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 || 1 || Controla la participación del color fijo y el color 0,0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para cada paleta habilitada, el administrador:&lt;br /&gt;
&lt;br /&gt;
# Comprueba si necesita actualizar el resultado del efecto.&lt;br /&gt;
# Prepara la base RGB o HSL si todavía falta.&lt;br /&gt;
# Calcula el efecto si el resultado anterior ya no sirve.&lt;br /&gt;
# Prepara los colores en formato SNES y solicita su transferencia.&lt;br /&gt;
# Confirma el ID procesado cuando la carga correspondiente se acepta.&lt;br /&gt;
&lt;br /&gt;
Si se mantiene el mismo efecto y no cambió la base, no hace falta calcularlo otra vez. Al cambiar el ID global se invalidan los resultados anteriores, no necesariamente las bases RGB y HSL.&lt;br /&gt;
&lt;br /&gt;
El ID global 0 también requiere una actualización: el sistema debe cargar de nuevo los colores de base para quitar el efecto anterior.&lt;br /&gt;
&lt;br /&gt;
=== Efecto local y concatenación ===&lt;br /&gt;
&lt;br /&gt;
Un recurso puede tener un efecto propio y recibir también el global. Por ejemplo, un sprite puede cambiar de tono y después oscurecerse junto con el nivel.&lt;br /&gt;
&lt;br /&gt;
El orden es:&lt;br /&gt;
&lt;br /&gt;
# Preparar el resultado del efecto local.&lt;br /&gt;
# Utilizarlo como base para el efecto global mediante la llamada de concatenación.&lt;br /&gt;
# Calcular el efecto global sobre esa base.&lt;br /&gt;
# Cargar el resultado combinado, sin mostrar antes la versión que solo tiene el efecto local.&lt;br /&gt;
&lt;br /&gt;
* La concatenación RGB se utiliza con efectos RGB.&lt;br /&gt;
* La concatenación HSL se utiliza con efectos HSL.&lt;br /&gt;
* Los recursos que comparten un destino de CGRAM comparten sus colores. Para mostrar dos efectos locales distintos, necesitan destinos que permitan mantener ambos resultados.&lt;br /&gt;
&lt;br /&gt;
=== Si no se acepta la transferencia ===&lt;br /&gt;
&lt;br /&gt;
* Calcular el efecto no significa que ya esté en CGRAM.&lt;br /&gt;
* Si la transferencia no se acepta, el administrador puede volver a intentar la actualización.&lt;br /&gt;
* Cuando corresponde, se mantiene el resultado anterior utilizable hasta poder sustituirlo.&lt;br /&gt;
* No se deben cargar primero los colores originales sin efecto: podrían verse así durante un frame antes del resultado correcto.&lt;br /&gt;
&lt;br /&gt;
== Cómo trabajan juntos ==&lt;br /&gt;
&lt;br /&gt;
El recorrido de un sprite dinámico reúne estas tareas:&lt;br /&gt;
&lt;br /&gt;
# Su lógica elige la pose y la versión de paleta.&lt;br /&gt;
# La asignación busca una paleta utilizable y prepara los colores si hace falta.&lt;br /&gt;
# La caché protege la pose ya cargada o prepara la carga de una nueva.&lt;br /&gt;
# El dibujo escribe los datos de sus piezas en los buffers OAM.&lt;br /&gt;
# El administrador de efectos prepara los cambios globales pendientes.&lt;br /&gt;
# NMI realiza las transferencias de gráficos y colores solicitadas.&lt;br /&gt;
&lt;br /&gt;
Compartir gráficos, compartir una paleta y compartir una rutina de dibujo son tres cosas distintas. Dynamic Xtreme puede aprovechar cada una sin obligar a que los recursos compartan también las demás.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21387</id>
		<title>es/Dynamic Xtreme UberASM guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21387"/>
		<updated>2026-10-25T18:00:23Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_UberASM_guide}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo utilizar Dynamic Xtreme desde UberASM para configurar los recursos de un nivel y crear cambios de gráficos y colores durante el juego. Se incluyen ejemplos para reservar paletas, elegir el espacio disponible para sprites dinámicos, crear animaciones y modificar los gráficos del jugador.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Tener UberASMTool instalado y configurado para insertar códigos en tu ROM.&lt;br /&gt;
* Tener Dynamic Xtreme instalado con las funciones necesarias para el ejemplo que quieras utilizar. Consulta la [[es/Dynamic_Xtreme_Quick_Start|guía de inicio rápido]] para su instalación.&lt;br /&gt;
&lt;br /&gt;
Para consultar los parámetros de una llamada o el uso de una variable, utiliza la [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]].&lt;br /&gt;
&lt;br /&gt;
Estas son las funcionalidades necesarias para cada ejemplo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Ejemplo !! Funcionalidades que debes habilitar&lt;br /&gt;
|-&lt;br /&gt;
| [[#Reservar paletas para otros recursos|Reservar paletas para otros recursos]]&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Elegir el espacio de VRAM para sprites dinámicos|Elegir el espacio de VRAM para sprites dinámicos]]&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;. Para dibujar esas poses con Dynamic Xtreme también necesitas &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Configurar la cantidad de datos que se transfieren por frame|Configurar la cantidad de datos que se transfieren por frame]]&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; para las cargas gráficas o &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; para las cargas de paletas; ambas si utilizas los dos tipos de carga.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Crear animaciones de gráficos|Crear animaciones de gráficos]]&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;, porque el ejemplo carga gráficos y una paleta. Añade &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; si cambias &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt; a 1 para utilizar el efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Cambiar paletas durante el juego|Cambiar paletas durante el juego]]&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; y, con &amp;lt;code&amp;gt;!PaletteGlobalEffect = 1&amp;lt;/code&amp;gt; como en el ejemplo, &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;. Para cargar sin efecto global, utiliza &amp;lt;code&amp;gt;!PaletteGlobalEffect = 0&amp;lt;/code&amp;gt;; en ese caso basta con &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Cambiar los gráficos del jugador|Cambiar los gráficos del jugador]]&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, junto con sus dependencias &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Aplicar un efecto global de paleta|Aplicar un efecto global de paleta]], fijo, cíclico o de transición&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La animación de gráficos de esta guía copia datos a un destino fijo de VRAM: no necesita &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;. Para conocer las rutinas y macros que habilita cada funcionalidad, consulta la [[es/Dynamic_Xtreme_ASM_API#Funcionalidades necesarias para utilizar la API|tabla de funcionalidades de la API]].&lt;br /&gt;
&lt;br /&gt;
== Preparar los ejemplos ==&lt;br /&gt;
&lt;br /&gt;
Cada ejemplo es independiente. Guarda el código de nivel en la carpeta correspondiente de UberASMTool y añádelo a su lista. Si reúnes varios ejemplos en un archivo, combina sus bloques &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; para no repetir las mismas etiquetas.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt; prepara datos durante la carga del nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; prepara las opciones al entrar al nivel. El ejemplo de reserva de paletas utiliza este bloque.&lt;br /&gt;
* &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; ejecuta el código durante el juego, una vez por frame.&lt;br /&gt;
&lt;br /&gt;
Los defines y macros de Dynamic Xtreme deben estar disponibles en UberASMTool mediante la integración realizada durante la instalación. Si utilizas gráficos, paletas o efectos adicionales, decláralos en el ASM mediante los includes correspondientes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MyResources.dynamicinfo&amp;quot;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/MyEffect.paleffect&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las rutas son relativas al ASM. Incluye únicamente los archivos que utiliza tu ejemplo. También puedes usar las carpetas tradicionales de Dynamic Xtreme, como se explica en [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
&lt;br /&gt;
Después de añadir o modificar estos recursos, instala primero Dynamic Xtreme y después UberASMTool. Si solo cambias la lógica del ASM, basta con volver a ejecutar UberASMTool.&lt;br /&gt;
&lt;br /&gt;
Los nombres &amp;lt;code&amp;gt;RAM_LIBRE_...&amp;lt;/code&amp;gt; de los ejemplos son marcadores: reemplázalos por direcciones de RAM libre antes de insertar el código. No son defines de Dynamic Xtreme. Reserva la cantidad de bytes indicada y utiliza direcciones distintas para variables que deban coexistir. Comprueba que no las utilicen el juego, Dynamic Xtreme, Lunar Magic u otros recursos; que una dirección esté libre en SMW original no garantiza que siga libre en tu ROM. Puedes buscar direcciones en el [https://www.smwcentral.net/?p=memorymap&amp;amp;game=smw&amp;amp;u=0&amp;amp;address=&amp;amp;sizeOperation=%3D&amp;amp;sizeValue=&amp;amp;region%5B%5D=ram&amp;amp;type=Empty&amp;amp;description= mapa de RAM de SMW Central filtrado por espacios vacíos].&lt;br /&gt;
&lt;br /&gt;
Si utilizas una dirección corta de RAM de SMW que no pertenece a la &#039;&#039;&#039;Direct Page&#039;&#039;&#039;, añade &amp;lt;code&amp;gt;|!addr&amp;lt;/code&amp;gt; para aplicar el remapeo correspondiente a LoROM o SA-1. Por ejemplo, al elegir la dirección del temporizador:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!AnimationTimer = RAM_LIBRE_ANIM_TIMER|!addr&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sustituye &amp;lt;code&amp;gt;RAM_LIBRE_ANIM_TIMER&amp;lt;/code&amp;gt; por la dirección elegida y conserva &amp;lt;code&amp;gt;|!addr&amp;lt;/code&amp;gt;. Las direcciones de Direct Page se acceden mediante la base D del contexto de ejecución y no utilizan este remapeo. Si eliges una dirección completa de 24 bits, comprueba su banco y que las instrucciones del ejemplo puedan acceder a ella; &amp;lt;code&amp;gt;|!addr&amp;lt;/code&amp;gt; está pensado aquí para las direcciones cortas fuera de Direct Page.&lt;br /&gt;
&lt;br /&gt;
== Reservar paletas para otros recursos ==&lt;br /&gt;
&lt;br /&gt;
Si una animación, un HUD u otro recurso necesita una paleta fija, conviene reservarla para que Dynamic Xtreme no la elija al asignar colores a los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
Para reservarla, escribe &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; en su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt;. Cada entrada ocupa 2 bytes. Por ejemplo, la paleta 9 utiliza el desplazamiento &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;: 9 × 2.&lt;br /&gt;
&lt;br /&gt;
Consulta el significado de esta tabla en [[es/Dynamic_Xtreme_ASM_API#Paletas y efecto global|Paletas y efecto global de la API]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$FFFE&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_ID+$12    ; Reservar la paleta 9&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para reservar varias, escribe el mismo valor en sus entradas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Paleta !! Desplazamiento&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| A || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| B || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| C || &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| D || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| E || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| F || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La reserva impide que la asignación automática reclame esa paleta; no carga colores por sí misma. Un recurso configurado para utilizarla manualmente todavía puede cambiar sus colores, por lo que no debes asignársela también a otro recurso que necesite una paleta diferente.&lt;br /&gt;
&lt;br /&gt;
== Elegir el espacio de VRAM para sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Los sprites dinámicos necesitan una parte de VRAM donde cargar sus poses. Elige un espacio que no estés utilizando para gráficos fijos del nivel.&lt;br /&gt;
&lt;br /&gt;
Puedes consultar el [[SMW_VRAM_Map#Levels|mapa de VRAM de SMW en SNESLab]] para ver qué regiones corresponden a SP1, SP2, SP3 y SP4.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para permitir que utilicen SP4:&lt;br /&gt;
&lt;br /&gt;
La rutina [[es/Dynamic_Xtreme_ASM_API#DynamicPoseSpaceConfig|DynamicPoseSpaceConfig]] recibe una de las configuraciones predefinidas.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si necesitas más espacio y el nivel lo permite, puedes elegir &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; para SP3 y SP4, o &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt; para SP2, SP3 y SP4. Hay más opciones, incluidas medias páginas y configuraciones para compartir espacio con el jugador o DSX.&lt;br /&gt;
&lt;br /&gt;
Los defines disponibles están en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y en la [[es/Dynamic_Xtreme_ASM_API#Configuraciones_de_espacio_para_poses_dinámicas|tabla de configuraciones de la API]]. Configura el espacio antes de que el nivel empiece a cargar poses; cambiarlo no elimina automáticamente las poses que ya estaban en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Crear una configuración propia ===&lt;br /&gt;
&lt;br /&gt;
Si necesitas combinar espacios de otra manera, utiliza [[es/Dynamic_Xtreme_ASM_API#DefineDynamicSpaceConfig|DefineDynamicSpaceConfig]]. Este ejemplo deja disponible la primera mitad de SP3 y todo SP4, y restringe el resto:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    ; SP1 y SP2 restringidos.&lt;br /&gt;
    %DefineDynamicSpaceConfig($00, $3F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; Primera mitad de SP3 disponible.&lt;br /&gt;
    %DefineDynamicSpaceConfig($40, $4F, $00)&lt;br /&gt;
&lt;br /&gt;
    ; Segunda mitad de SP3 restringida.&lt;br /&gt;
    %DefineDynamicSpaceConfig($50, $5F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; SP4 disponible.&lt;br /&gt;
    %DefineDynamicSpaceConfig($60, $7F, $00)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los dos primeros parámetros son el primer y el último bloque de 16×16, incluidos ambos. El tercero utiliza &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; para permitir poses dinámicas o &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; para restringir el espacio. Los IDs avanzan de izquierda a derecha y de arriba abajo, con 8 bloques por fila. La [[es/Dynamic_Xtreme_ASM_API#DefineDynamicSpaceConfig|documentación de la macro]] incluye la tabla de numeración completa.&lt;br /&gt;
&lt;br /&gt;
Este ejemplo sustituye la llamada a la configuración predefinida: no ejecutes las dos configuraciones una después de otra. Ajusta los rangos para cubrir los bloques &amp;lt;code&amp;gt;$00–$7F&amp;lt;/code&amp;gt; sin superponerlos y restringe las zonas que necesiten conservar otros gráficos del nivel. Requiere &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;, igual que el ejemplo anterior.&lt;br /&gt;
&lt;br /&gt;
== Configurar la cantidad de datos que se transfieren por frame ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; indica cuántos bytes pueden programar las cargas normales de Dynamic Xtreme durante un frame. Lo comparten las poses dinámicas, las animaciones y las demás transferencias realizadas con sus macros.&lt;br /&gt;
&lt;br /&gt;
Consulta estas variables en [[es/Dynamic_Xtreme_ASM_API#Contadores y cantidad de datos por frame|Contadores y cantidad de datos por frame de la API]].&lt;br /&gt;
&lt;br /&gt;
El valor predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Este ejemplo lo aumenta a &amp;lt;code&amp;gt;$0A00&amp;lt;/code&amp;gt;, equivalente a 2560 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0A00&lt;br /&gt;
    STA.l DX_Dynamic_MaxDataPerFrame&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Subirlo permite intentar más cargas durante el mismo frame, pero no aumenta el tiempo que tiene SNES para copiarlas. Si la cantidad total es excesiva, pueden aparecer problemas visuales. Ajusta el valor según el nivel y comprueba el resultado con sus sprites y animaciones funcionando juntos.&lt;br /&gt;
&lt;br /&gt;
Las macros normales devuelven el carry desactivado si una carga no cabe en el límite. En ese caso, conserva lo que ya se muestra y vuelve a intentarlo después. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; se saltan la comprobación y también suman sus bytes al total.&lt;br /&gt;
&lt;br /&gt;
== Crear animaciones de gráficos ==&lt;br /&gt;
&lt;br /&gt;
Este ejemplo crea una animación de gráficos: una tabla indica dónde empieza cada imagen, un temporizador controla cuándo cambiarla y la imagen anterior se mantiene si no se acepta la transferencia.&lt;br /&gt;
&lt;br /&gt;
Utiliza [[es/Dynamic_Xtreme_ASM_API#TransferToVRAM|TransferToVRAM]] para los cambios de gráficos, su [[es/Dynamic_Xtreme_ASM_API#Variantes Forced|variante Forced]] para la carga inicial y [[es/Dynamic_Xtreme_ASM_API#TransferPaletteResource|TransferPaletteResource]] para los colores. Consulta esos enlaces para sus parámetros, registros y resultados.&lt;br /&gt;
&lt;br /&gt;
Declara los archivos del ejemplo en &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Aquí pon RAM libre: un byte distinto para cada variable.&lt;br /&gt;
!CurrentPoseIndex = RAM_LIBRE_ANIM_POSE&lt;br /&gt;
!AnimationTimer = RAM_LIBRE_ANIM_TIMER&lt;br /&gt;
!PaletteLoaded = RAM_LIBRE_ANIM_PALETA&lt;br /&gt;
&lt;br /&gt;
; Frames de espera antes de intentar el siguiente cambio.&lt;br /&gt;
!TimePerPose = $03&lt;br /&gt;
&lt;br /&gt;
; Bytes de cada imagen: un tile de 8x8 en 4bpp ocupa $0020.&lt;br /&gt;
!DataSend = $0200&lt;br /&gt;
&lt;br /&gt;
; Cantidad de imágenes utilizadas.&lt;br /&gt;
!NumberOfPoses = $05&lt;br /&gt;
&lt;br /&gt;
; Origen: recurso instalado. También puedes usar !AN2Buffer2.&lt;br /&gt;
!Source = !ResourceSMMArrow&lt;br /&gt;
&lt;br /&gt;
; Dirección de destino en VRAM.&lt;br /&gt;
!Destination = !BG2Line0&lt;br /&gt;
&lt;br /&gt;
; Paleta instalada y primer color de destino.&lt;br /&gt;
!Palette = &amp;quot;SMMArrowPal&amp;quot;&lt;br /&gt;
!PaletteDestination = $71&lt;br /&gt;
&lt;br /&gt;
; 0 = sin efecto global; 1 = recibe el efecto global.&lt;br /&gt;
!PaletteGlobalEffect = 0&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    STZ !CurrentPoseIndex&lt;br /&gt;
    LDA #!TimePerPose&lt;br /&gt;
    STA !AnimationTimer&lt;br /&gt;
    STZ !PaletteLoaded&lt;br /&gt;
&lt;br /&gt;
    %ForcedTransferToVRAM(#!Destination, #!Source, #((!Source&amp;gt;&amp;gt;16)&amp;amp;$FF), #!DataSend)&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteLoaded&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; Reintentar la paleta si no se aceptó durante init.&lt;br /&gt;
    LDA !PaletteLoaded&lt;br /&gt;
    BNE .Animate&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCS .PaletteReady&lt;br /&gt;
    RTL&lt;br /&gt;
.PaletteReady&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteLoaded&lt;br /&gt;
&lt;br /&gt;
.Animate&lt;br /&gt;
    LDA !AnimationTimer&lt;br /&gt;
    BEQ .NextPose&lt;br /&gt;
    DEC !AnimationTimer&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
.NextPose&lt;br /&gt;
    LDA !CurrentPoseIndex&lt;br /&gt;
    INC A&lt;br /&gt;
    CMP #!NumberOfPoses&lt;br /&gt;
    BCC .SelectPose&lt;br /&gt;
    LDA #$00&lt;br /&gt;
.SelectPose&lt;br /&gt;
    STA $05&lt;br /&gt;
    ASL&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l PosesTable,x&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC.w #!Source&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    %TransferToVRAM(#!Destination, $00, #((!Source&amp;gt;&amp;gt;16)&amp;amp;$FF), #!DataSend)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA $05&lt;br /&gt;
    STA !CurrentPoseIndex&lt;br /&gt;
    LDA #!TimePerPose&lt;br /&gt;
    STA !AnimationTimer&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
PosesTable:&lt;br /&gt;
    dw $0000&lt;br /&gt;
    dw !DataSend*$01&lt;br /&gt;
    dw !DataSend*$02&lt;br /&gt;
    dw !DataSend*$03&lt;br /&gt;
    dw !DataSend*$04&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!TimePerPose&amp;lt;/code&amp;gt;: tiempo de espera. Con &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;, el cambio se intenta cada cuatro frames: tres para descontar el temporizador y uno para realizar el cambio.&lt;br /&gt;
* &amp;lt;code&amp;gt;!DataSend&amp;lt;/code&amp;gt;: bytes de cada imagen. &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; equivale a 16 tiles de 8×8 en 4bpp.&lt;br /&gt;
* &amp;lt;code&amp;gt;!NumberOfPoses&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PosesTable&amp;lt;/code&amp;gt;: cantidad de imágenes y sus desplazamientos dentro del origen. El ejemplo utiliza las primeras cinco imágenes de &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;. Si añades más, amplía también la tabla.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Source&amp;lt;/code&amp;gt;: dirección de los gráficos. El ejemplo lee directamente &amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt;; para animar gráficos ya preparados por Lunar Magic puedes usar &amp;lt;code&amp;gt;!AN2Buffer2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Destination&amp;lt;/code&amp;gt;: zona de VRAM que se actualizará. Coloca en el nivel tiles que utilicen esa zona y comprueba que otro recurso no la sobrescriba.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteDestination&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt;: paleta, primer color de destino y participación en el efecto global.&lt;br /&gt;
&lt;br /&gt;
Reemplaza los tres marcadores de RAM del principio por direcciones disponibles durante todo el nivel: cada variable necesita un byte propio. No son scratch temporales. &amp;lt;code&amp;gt;!PaletteLoaded&amp;lt;/code&amp;gt; permite reintentar una carga de paleta rechazada sin repetirla después de que haya sido aceptada.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt; se generan al instalar el DynamicInfo y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres se normalizan en PascalCase eliminando separadores; en este caso se conservan las mayúsculas de &amp;lt;code&amp;gt;SMMArrow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Todas las imágenes utilizadas deben quedar en el mismo banco del origen. La carga inicial de gráficos utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;; los siguientes cambios respetan el límite de datos por frame. Si una carga se rechaza, el código conserva la imagen anterior y vuelve a intentarla en el siguiente frame, sin avanzar el índice ni reiniciar el temporizador.&lt;br /&gt;
&lt;br /&gt;
El temporizador avanza cada vez que se ejecuta &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;. Si quieres detener la animación durante la pausa o cuando se congela la acción, puedes comprobar &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; antes de descontarlo.&lt;br /&gt;
&lt;br /&gt;
== Cambiar paletas durante el juego ==&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; permiten cargar colores y mantener actualizadas las copias que utilizan SMW y Dynamic Xtreme. También se encargan de preparar los efectos de paleta, por lo que no necesitas copiar buffers ni borrar indicadores a mano.&lt;br /&gt;
&lt;br /&gt;
Este ejemplo utiliza [[es/Dynamic_Xtreme_ASM_API#TransferPaletteResource|TransferPaletteResource]]; consulta su entrada en la API para los parámetros y el significado del carry.&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza &amp;lt;code&amp;gt;SMMArrowPal.bin&amp;lt;/code&amp;gt;, un archivo de 15 colores (&amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes), y cambia los colores 1-F de la paleta 7. El color 0 queda sin modificar.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;, declara los gráficos como recurso general y la paleta en &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ASM del nivel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Aquí pon una RAM libre de un byte.&lt;br /&gt;
!PaletteChangePending = RAM_LIBRE_CAMBIO_PALETA&lt;br /&gt;
&lt;br /&gt;
!Palette = &amp;quot;SMMArrowPal&amp;quot;&lt;br /&gt;
!PaletteDestination = $71&lt;br /&gt;
!PaletteGlobalEffect = 1&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteChangePending&lt;br /&gt;
    ; Continuar con el primer intento de carga.&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA !PaletteChangePending&lt;br /&gt;
    BNE .TryTransfer&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.TryTransfer&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    ; Confirmar el cambio solo si la llamada fue aceptada.&lt;br /&gt;
    STZ !PaletteChangePending&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reemplaza &amp;lt;code&amp;gt;RAM_LIBRE_CAMBIO_PALETA&amp;lt;/code&amp;gt; por una dirección de RAM libre de un byte, disponible durante todo el nivel. &amp;lt;code&amp;gt;!PaletteChangePending&amp;lt;/code&amp;gt; se pone en 1 al solicitar el cambio y solo vuelve a 0 cuando la macro devuelve el carry activado. Si la llamada falla, el cambio queda pendiente y se reintenta en el siguiente frame. Una vez aceptado, no se repite la carga.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt; selecciona el recurso y &amp;lt;code&amp;gt;!PaletteDestination&amp;lt;/code&amp;gt; el primer color de destino. &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt;, utilizado como último parámetro de la macro, elige cómo se carga:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;: prepara los colores originales para que reciban el efecto global antes de mostrarse. También deja la paleta preparada si todavía no has seleccionado un efecto.&lt;br /&gt;
* &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;: carga los colores sin efecto global y excluye esa paleta del efecto. Además actualiza los buffers de SMW, necesarios para evitar problemas de colores durante la animación de victoria del goal.&lt;br /&gt;
&lt;br /&gt;
Para cargar la misma paleta sin efecto global, cambia únicamente este define; conserva la comprobación del carry:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!PaletteGlobalEffect = 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si los efectos están deshabilitados en la instalación, ambas opciones realizan una carga directa. Cuando están habilitados y utilizas &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, el sistema carga el resultado ya procesado; no se muestra primero la paleta sin efecto durante un frame.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; utiliza los defines &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt;, generados desde &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; del DynamicInfo y publicados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra. En este caso se conserva &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; tal como está escrito.&lt;br /&gt;
&lt;br /&gt;
Para solicitar de nuevo el cambio durante el juego, pon &amp;lt;code&amp;gt;!PaletteChangePending&amp;lt;/code&amp;gt; en 1 cuando se cumpla la condición que elijas. No lo hagas cada frame si la paleta no cambia. En una carga directa, el carry activado indica que se programó la transferencia; con efecto global, indica que los colores originales quedaron preparados, no que el resultado ya esté en pantalla.&lt;br /&gt;
&lt;br /&gt;
La opción de efecto se aplica a toda la paleta de 16 colores. Si cargas colores para recibir un efecto global, prepara todos sus colores visibles, como los 15 de este ejemplo; no cambies solo unos pocos esperando conservar una base que todavía no has preparado.&lt;br /&gt;
&lt;br /&gt;
Si eliges una paleta de sprites 8-F para un uso fijo, resérvala primero como se explica al comienzo del artículo. Estas macros no realizan asignación automática. Para cargar desde una dirección, un puntero o una tabla, consulta [[es/Dynamic_Xtreme_ASM_API#Cargar_colores_con_TransferPalette|Cargar colores con TransferPalette en la API]].&lt;br /&gt;
&lt;br /&gt;
== Cambiar los gráficos del jugador ==&lt;br /&gt;
&lt;br /&gt;
Este ejemplo alterna entre el jugador original y Geno al pulsar arriba. Sus defines permiten elegir los gráficos y las cuatro paletas: Mario, Luigi, Mario con fuego y Luigi con fuego. También vuelve a seleccionar la paleta cuando cambia el estado del jugador.&lt;br /&gt;
&lt;br /&gt;
Necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; habilitado. Los gráficos personalizados deben utilizar la misma organización de poses que los originales; cambiar el origen no adapta un spritesheet de otro formato.&lt;br /&gt;
&lt;br /&gt;
El código utiliza las [[es/Dynamic_Xtreme_ASM_API#Jugador y Yoshi|variables del jugador]] y las macros [[es/Dynamic_Xtreme_ASM_API#Div y DivW|DivW]], [[es/Dynamic_Xtreme_ASM_API#TransferPaletteFromPointer|TransferPaletteFromPointer]] y [[es/Dynamic_Xtreme_ASM_API#TransferPaletteFromAddress|TransferPaletteFromAddress]]. Sus entradas de la API explican los parámetros, registros y resultados de cada llamada.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/Geno.dynamicinfo&amp;lt;/code&amp;gt;, declara:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    Geno.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    GenoPal.bin&lt;br /&gt;
    GenoPalPlayer2.bin&lt;br /&gt;
    FireGenoPal.bin&lt;br /&gt;
    FireGenoPalPlayer2.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/Geno.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Aquí pon una RAM libre de dos bytes consecutivos.&lt;br /&gt;
!Last0D82 = RAM_LIBRE_JUGADOR_2_BYTES&lt;br /&gt;
&lt;br /&gt;
; Gráficos del jugador personalizado.&lt;br /&gt;
!PlayerGFXResource = !ResourceGeno&lt;br /&gt;
&lt;br /&gt;
; Paletas: jugador 1, jugador 2 y sus variantes con fuego.&lt;br /&gt;
!PlayerGFXPalette = !PaletteGenoPal&lt;br /&gt;
!PlayerGFXPalettePlayer2 = !PaletteGenoPalPlayer2&lt;br /&gt;
!PlayerGFXFirePalette = !PaletteFireGenoPal&lt;br /&gt;
!PlayerGFXFirePalettePlayer2 = !PaletteFireGenoPalPlayer2&lt;br /&gt;
&lt;br /&gt;
; Botón de cambio: $08 = arriba.&lt;br /&gt;
!ChangeButton = $08&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA !Last0D82&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA !ButtonDown_BYETUDLR&lt;br /&gt;
    AND #!ChangeButton&lt;br /&gt;
    BNE .Change&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    CMP !Last0D82&lt;br /&gt;
    BNE .Reload&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
.Change&lt;br /&gt;
    LDA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    CMP.b #!GFX32Buffer&amp;gt;&amp;gt;16&lt;br /&gt;
    BEQ .ChooseGeno&lt;br /&gt;
    JMP .Mario&lt;br /&gt;
.ChooseGeno&lt;br /&gt;
    JMP .Geno&lt;br /&gt;
&lt;br /&gt;
.Reload&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    CMP.b #!GFX32Buffer&amp;gt;&amp;gt;16&lt;br /&gt;
    BNE .Geno&lt;br /&gt;
    JMP .Mario&lt;br /&gt;
&lt;br /&gt;
.Geno&lt;br /&gt;
    ; Obtener 0, 1, 2 o 3 según jugador y estado de fuego.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    SEC&lt;br /&gt;
    SBC #!PlayerBasePalette&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    %DivW($01, $00, #$14)&lt;br /&gt;
&lt;br /&gt;
    ; Cada dirección de GenoPals ocupa tres bytes.&lt;br /&gt;
    LDA !DivisionResult&lt;br /&gt;
    ASL&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC !DivisionResult&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    ; Conservar el origen elegido y preparar los colores 2-5.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l GenoPals,x&lt;br /&gt;
    STA $03&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$0002&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.l GenoPals+2,x&lt;br /&gt;
    STA $02&lt;br /&gt;
    STA $05&lt;br /&gt;
&lt;br /&gt;
    %TransferPaletteFromPointer($00, #$82, $0008, 0)&lt;br /&gt;
    BCS .ApplyGeno&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.ApplyGeno&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!PlayerGFXResource&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!PlayerGFXResource&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
&lt;br /&gt;
    ; La rutina del jugador carga los colores 6-F.&lt;br /&gt;
    LDA $03&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$000A&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA $05&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    JMP .ConfirmSelection&lt;br /&gt;
&lt;br /&gt;
.Mario&lt;br /&gt;
    %TransferPaletteFromAddress(!PlayerPaletteColor2To5, #$82, $0008, 0)&lt;br /&gt;
    BCS .ApplyMario&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.ApplyMario&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!GFX32Buffer&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    LDA.w #(!GFX32Buffer&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
.ConfirmSelection&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA !Last0D82&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
GenoPals:&lt;br /&gt;
    dl !PlayerGFXPalette&lt;br /&gt;
    dl !PlayerGFXPalettePlayer2&lt;br /&gt;
    dl !PlayerGFXFirePalette&lt;br /&gt;
    dl !PlayerGFXFirePalettePlayer2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!PlayerGFXResource&amp;lt;/code&amp;gt;: gráficos del personaje personalizado.&lt;br /&gt;
* Los cuatro defines &amp;lt;code&amp;gt;!PlayerGFX...Palette...&amp;lt;/code&amp;gt;: direcciones de sus paletas, en el orden de la tabla &amp;lt;code&amp;gt;GenoPals&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ChangeButton&amp;lt;/code&amp;gt;: botón que alterna entre los personajes. Utiliza los bits del control &amp;lt;code&amp;gt;BYETUDLR&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; corresponde a arriba.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Last0D82&amp;lt;/code&amp;gt;: reemplaza &amp;lt;code&amp;gt;RAM_LIBRE_JUGADOR_2_BYTES&amp;lt;/code&amp;gt; por una dirección de RAM libre con dos bytes consecutivos disponibles. Guarda la selección de paleta del juego; ninguno de esos bytes debe estar ocupado por otro código.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGeno&amp;lt;/code&amp;gt; y los defines &amp;lt;code&amp;gt;!PaletteGenoPal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteGenoPalPlayer2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteFireGenoPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteFireGenoPalPlayer2&amp;lt;/code&amp;gt; se generan desde el DynamicInfo y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres usan PascalCase eliminando espacios, guiones y guiones bajos, y conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
Cada archivo de paleta contiene los colores 1-F. Se omite su primer color para copiar los colores 2-5; los últimos diez comienzan en &amp;lt;code&amp;gt;+$0A&amp;lt;/code&amp;gt; y los utiliza la rutina del jugador.&lt;br /&gt;
&lt;br /&gt;
Las cargas de los colores 2-5 utilizan &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, que también actualiza los buffers de SMW. El ejemplo no confirma el cambio de gráficos si esa transferencia es rechazada. Un cambio pendiente por el estado del jugador se vuelve a intentar mientras no coincida con &amp;lt;code&amp;gt;!Last0D82&amp;lt;/code&amp;gt;; si se rechaza un cambio solicitado con el botón, vuelve a pulsarlo.&lt;br /&gt;
&lt;br /&gt;
El código distingue al jugador original por el banco de &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt;. Si lo adaptas para alternar entre varios personajes personalizados en ROM, necesitarás otra forma de recordar cuál está seleccionado.&lt;br /&gt;
&lt;br /&gt;
Este ejemplo carga la paleta del jugador sin efecto global. No basta con cambiar a &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; el parámetro de una carga de cuatro colores para añadirle un efecto: en ese caso hay que preparar todos los colores visibles de la paleta 8 y respetar su carga especial.&lt;br /&gt;
&lt;br /&gt;
== Aplicar un efecto global de paleta ==&lt;br /&gt;
&lt;br /&gt;
Los siguientes ejemplos permiten aplicar un efecto fijo, recorrer efectos en un ciclo o realizar una transición que se detiene al terminar. Puedes elegir cada paleta por separado e incluir el color fijo. Los códigos de ciclo y transición también permiten configurar la velocidad con &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los tres configuran las [[es/Dynamic_Xtreme_ASM_API#Paletas y efecto global|variables del efecto global]] y las de [[es/Dynamic_Xtreme_ASM_API#Color fijo y primer color de la paleta|color fijo y primer color de la paleta]]. Consulta sus entradas en la API para el significado de cada variable.&lt;br /&gt;
&lt;br /&gt;
En los archivos &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; selecciona el tipo de efecto. Los ratios utilizan valores de 0 a 127 y los valores &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt;, de 0 a 31.&lt;br /&gt;
&lt;br /&gt;
=== Elegir las paletas afectadas ===&lt;br /&gt;
&lt;br /&gt;
En cada código, cambia &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt; a 1 para incluir la paleta correspondiente o a 0 para excluirla. &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; controla el color fijo y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt; permite incluir también el color 0,0.&lt;br /&gt;
&lt;br /&gt;
Las máscaras &amp;lt;code&amp;gt;!EnableBG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableSP&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColors&amp;lt;/code&amp;gt; se calculan a partir de esos ajustes. No necesitas modificarlas a mano. En la API actual, el bit bajo corresponde a la primera paleta de cada grupo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor del bit !! Paleta de fondo !! Paleta de sprites&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || 0 || 8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || 1 || 9&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || 2 || A&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || 3 || B&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || 4 || C&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || 5 || D&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || 6 || E&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; || 7 || F&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
El color fijo y el color 0,0 utilizan &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt;: bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; y bit &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, respectivamente.&lt;br /&gt;
&lt;br /&gt;
En sprites con asignación dinámica, configura también el bit E de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;. Si cargas paletas mediante &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, su último parámetro determina si esas paletas participan en el efecto global. Evita que otro código vuelva a escribir máscaras distintas sin tener en cuenta esa configuración.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto fijo ===&lt;br /&gt;
&lt;br /&gt;
Este ejemplo aplica el efecto que indiques en &amp;lt;code&amp;gt;!PaletteEffetID&amp;lt;/code&amp;gt;. La configuración mostrada habilita todas las paletas y el color fijo, y selecciona el último efecto de &amp;lt;code&amp;gt;DecreaseSaturation&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Guarda el siguiente contenido en &amp;lt;code&amp;gt;DynamicXtreme/DecreaseSaturation.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 4, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 8, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 12, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 16, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 20, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 25, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 29, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 33, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 37, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 41, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 45, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 49, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 53, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 57, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 61, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 66, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 70, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 74, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 78, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 82, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 86, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 90, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 94, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 98, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 102, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 107, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 111, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 115, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 119, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 123, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 11}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El archivo define 32 efectos. &amp;lt;code&amp;gt;EffectType = 11&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;Channel2 = 0&amp;lt;/code&amp;gt; indica que se reduce la saturación y &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; controla cuánto. El último efecto utiliza 127, que aplica el cambio completo.&lt;br /&gt;
&lt;br /&gt;
El código ASM es:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/DecreaseSaturation.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 1&lt;br /&gt;
!P2 = 1&lt;br /&gt;
!P3 = 1&lt;br /&gt;
!P4 = 1&lt;br /&gt;
!P5 = 1&lt;br /&gt;
!P6 = 1&lt;br /&gt;
!P7 = 1&lt;br /&gt;
&lt;br /&gt;
!P8 = 1&lt;br /&gt;
!P9 = 1&lt;br /&gt;
!PA = 1&lt;br /&gt;
!PB = 1&lt;br /&gt;
!PC = 1&lt;br /&gt;
!PD = 1&lt;br /&gt;
!PE = 1&lt;br /&gt;
!PF = 1&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Efecto que se aplica al entrar al nivel.&lt;br /&gt;
!PaletteEffetID = !PaletteEffectIDDecreaseSaturation31&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;: paletas afectadas.&lt;br /&gt;
* &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: participación de esos colores.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteEffetID&amp;lt;/code&amp;gt;: efecto seleccionado. Puedes utilizar cualquier ID generado desde tu archivo de efectos, no solo el último de este ejemplo.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation31&amp;lt;/code&amp;gt; se generan desde el &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando espacios, guiones y guiones bajos, y conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
La selección se realiza en &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;; no hace falta repetirla cada frame. Para quitar el efecto, escribe 0 en el ID global y deja las paletas habilitadas para que el sistema restaure sus colores originales:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hacer que el efecto se repita en un ciclo ===&lt;br /&gt;
&lt;br /&gt;
Este ejemplo recorre una secuencia de efectos y vuelve al primero. Puedes configurar la velocidad, el primer y último ID y las paletas afectadas. La configuración mostrada incluye solo la paleta 0 y el color fijo.&lt;br /&gt;
&lt;br /&gt;
Guarda el siguiente contenido en &amp;lt;code&amp;gt;DynamicXtreme/Hue.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 1, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 2, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 3, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 4, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 5, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 6, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 7, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 8, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 9, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 10, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 11, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 12, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 13, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 14, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 15, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 16, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 17, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 18, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 19, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 20, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 21, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 22, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 23, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 24, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 25, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 26, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 27, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 28, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 29, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 30, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 31, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 31, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El archivo define 32 efectos de tono. &amp;lt;code&amp;gt;EffectType = 9&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio1 = 127&amp;lt;/code&amp;gt; aplica por completo el tono seleccionado.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Hue.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 0&lt;br /&gt;
!P2 = 0&lt;br /&gt;
!P3 = 0&lt;br /&gt;
!P4 = 0&lt;br /&gt;
!P5 = 0&lt;br /&gt;
!P6 = 0&lt;br /&gt;
!P7 = 0&lt;br /&gt;
&lt;br /&gt;
!P8 = 0&lt;br /&gt;
!P9 = 0&lt;br /&gt;
!PA = 0&lt;br /&gt;
!PB = 0&lt;br /&gt;
!PC = 0&lt;br /&gt;
!PD = 0&lt;br /&gt;
!PE = 0&lt;br /&gt;
!PF = 0&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Valores permitidos: $00, $01, $03, $07, $0F, $1F, $3F, $7F y $FF.&lt;br /&gt;
!Delay = $03&lt;br /&gt;
&lt;br /&gt;
!StartingPaletteEffetID = !PaletteEffectIDHue0&lt;br /&gt;
!EndPaletteEffetID = !PaletteEffectIDHue31&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #!Delay&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!EndPaletteEffetID&lt;br /&gt;
    BCS .Restart&lt;br /&gt;
    INC A&lt;br /&gt;
    BRA .Store&lt;br /&gt;
.Restart&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
.Store&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: colores afectados.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;: separación entre cambios. &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; cambia cada frame, &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; cada dos, &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; cada cuatro y &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; cada ocho. Utiliza únicamente los valores indicados en el comentario.&lt;br /&gt;
* &amp;lt;code&amp;gt;!StartingPaletteEffetID&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EndPaletteEffetID&amp;lt;/code&amp;gt;: primer y último efecto del ciclo. Deben pertenecer a una secuencia de IDs consecutivos, con el inicio menor o igual que el final.&lt;br /&gt;
&lt;br /&gt;
El ciclo muestra el último ID antes de volver al primero. Utiliza &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; para marcar el momento de los cambios; por ello, el primer intervalo depende del valor que tenga ese contador al entrar al nivel. Si quieres detenerlo al congelarse la acción, comprueba también &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt; al comienzo de &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDHue0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDHue31&amp;lt;/code&amp;gt; se generan desde el &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores; en este caso conserva &amp;lt;code&amp;gt;Hue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Hacer una transición que se detiene al terminar ===&lt;br /&gt;
&lt;br /&gt;
Este ejemplo avanza desde el efecto inicial hasta el final y mantiene ese último resultado. Puedes configurar las paletas afectadas, el color fijo, la velocidad y el rango de IDs.&lt;br /&gt;
&lt;br /&gt;
Guarda el siguiente contenido en &amp;lt;code&amp;gt;DynamicXtreme/Night.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 0, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 4, &amp;quot;Ratio2&amp;quot;: 4, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 8, &amp;quot;Ratio2&amp;quot;: 8, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 12, &amp;quot;Ratio2&amp;quot;: 12, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 16, &amp;quot;Ratio2&amp;quot;: 16, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 20, &amp;quot;Ratio2&amp;quot;: 20, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 25, &amp;quot;Ratio2&amp;quot;: 25, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 29, &amp;quot;Ratio2&amp;quot;: 29, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 33, &amp;quot;Ratio2&amp;quot;: 33, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 37, &amp;quot;Ratio2&amp;quot;: 37, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 41, &amp;quot;Ratio2&amp;quot;: 41, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 45, &amp;quot;Ratio2&amp;quot;: 45, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 49, &amp;quot;Ratio2&amp;quot;: 49, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 53, &amp;quot;Ratio2&amp;quot;: 53, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 57, &amp;quot;Ratio2&amp;quot;: 57, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 61, &amp;quot;Ratio2&amp;quot;: 61, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 66, &amp;quot;Ratio2&amp;quot;: 66, &amp;quot;EffectType&amp;quot;: 2}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La transición tiene 17 pasos. &amp;lt;code&amp;gt;EffectType = 2&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixRG&amp;lt;/code&amp;gt;: reduce el rojo y el verde sin modificar el azul. Los ratios aumentan de 0 a 66 para oscurecer los colores gradualmente sin eliminar por completo el rojo y el verde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Night.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 1&lt;br /&gt;
!P2 = 1&lt;br /&gt;
!P3 = 1&lt;br /&gt;
!P4 = 1&lt;br /&gt;
!P5 = 1&lt;br /&gt;
!P6 = 1&lt;br /&gt;
!P7 = 1&lt;br /&gt;
&lt;br /&gt;
!P8 = 1&lt;br /&gt;
!P9 = 1&lt;br /&gt;
!PA = 1&lt;br /&gt;
!PB = 1&lt;br /&gt;
!PC = 1&lt;br /&gt;
!PD = 1&lt;br /&gt;
!PE = 1&lt;br /&gt;
!PF = 1&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Valores permitidos: $00, $01, $03, $07, $0F, $1F, $3F, $7F y $FF.&lt;br /&gt;
!Delay = $03&lt;br /&gt;
&lt;br /&gt;
!StartingPaletteEffetID = !PaletteEffectIDNight0&lt;br /&gt;
!EndPaletteEffetID = !PaletteEffectIDNight16&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #!Delay&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!EndPaletteEffetID&lt;br /&gt;
    BCS .Finished&lt;br /&gt;
    INC A&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
.Finished&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: colores afectados.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;: tiempo entre cambios, con los mismos valores permitidos en el ejemplo de ciclo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!StartingPaletteEffetID&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EndPaletteEffetID&amp;lt;/code&amp;gt;: primer y último efecto. Deben ser IDs consecutivos en orden ascendente.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDNight16&amp;lt;/code&amp;gt; se generan desde &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres usan PascalCase eliminando separadores; aquí se conserva &amp;lt;code&amp;gt;Night&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Este ejemplo cambia entre efectos de mezcla. Para una transición hacia otra paleta completa, utiliza &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt;, explicados en [[es/Dynamic_Xtreme_files_and_formats#Transiciones_de_paleta|Archivos y formatos]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21386</id>
		<title>es/Dynamic Xtreme UberASM guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21386"/>
		<updated>2026-10-25T17:56:53Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_UberASM_guide}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo utilizar Dynamic Xtreme desde UberASM para configurar los recursos de un nivel y crear cambios de gráficos y colores durante el juego. Se incluyen ejemplos para reservar paletas, elegir el espacio disponible para sprites dinámicos, crear animaciones y modificar los gráficos del jugador.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Tener UberASMTool instalado y configurado para insertar códigos en tu ROM.&lt;br /&gt;
* Tener Dynamic Xtreme instalado con las funciones necesarias para el ejemplo que quieras utilizar. Consulta la [[es/Dynamic_Xtreme_Quick_Start|guía de inicio rápido]] para su instalación.&lt;br /&gt;
&lt;br /&gt;
Para consultar los parámetros de una llamada o el uso de una variable, utiliza la [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]].&lt;br /&gt;
&lt;br /&gt;
Estas son las funcionalidades necesarias para cada ejemplo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Ejemplo !! Funcionalidades que debes habilitar&lt;br /&gt;
|-&lt;br /&gt;
| [[#Reservar paletas para otros recursos|Reservar paletas para otros recursos]]&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Elegir el espacio de VRAM para sprites dinámicos|Elegir el espacio de VRAM para sprites dinámicos]]&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;. Para dibujar esas poses con Dynamic Xtreme también necesitas &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Configurar la cantidad de datos que se transfieren por frame|Configurar la cantidad de datos que se transfieren por frame]]&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; para las cargas gráficas o &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; para las cargas de paletas; ambas si utilizas los dos tipos de carga.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Crear animaciones de gráficos|Crear animaciones de gráficos]]&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;, porque el ejemplo carga gráficos y una paleta. Añade &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; si cambias &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt; a 1 para utilizar el efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Cambiar paletas durante el juego|Cambiar paletas durante el juego]]&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; y, con &amp;lt;code&amp;gt;!PaletteGlobalEffect = 1&amp;lt;/code&amp;gt; como en el ejemplo, &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;. Para cargar sin efecto global, utiliza &amp;lt;code&amp;gt;!PaletteGlobalEffect = 0&amp;lt;/code&amp;gt;; en ese caso basta con &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Cambiar los gráficos del jugador|Cambiar los gráficos del jugador]]&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, junto con sus dependencias &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Aplicar un efecto global de paleta|Aplicar un efecto global de paleta]], fijo, cíclico o de transición&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La animación de gráficos de esta guía copia datos a un destino fijo de VRAM: no necesita &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;. Para conocer las rutinas y macros que habilita cada funcionalidad, consulta la [[es/Dynamic_Xtreme_ASM_API#Funcionalidades necesarias para utilizar la API|tabla de funcionalidades de la API]].&lt;br /&gt;
&lt;br /&gt;
== Preparar los ejemplos ==&lt;br /&gt;
&lt;br /&gt;
Cada ejemplo es independiente. Guarda el código de nivel en la carpeta correspondiente de UberASMTool y añádelo a su lista. Si reúnes varios ejemplos en un archivo, combina sus bloques &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; para no repetir las mismas etiquetas.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt; prepara datos durante la carga del nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; prepara las opciones al entrar al nivel. El ejemplo de reserva de paletas utiliza este bloque.&lt;br /&gt;
* &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; ejecuta el código durante el juego, una vez por frame.&lt;br /&gt;
&lt;br /&gt;
Los defines y macros de Dynamic Xtreme deben estar disponibles en UberASMTool mediante la integración realizada durante la instalación. Si utilizas gráficos, paletas o efectos adicionales, decláralos en el ASM mediante los includes correspondientes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MyResources.dynamicinfo&amp;quot;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/MyEffect.paleffect&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las rutas son relativas al ASM. Incluye únicamente los archivos que utiliza tu ejemplo. También puedes usar las carpetas tradicionales de Dynamic Xtreme, como se explica en [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
&lt;br /&gt;
Después de añadir o modificar estos recursos, instala primero Dynamic Xtreme y después UberASMTool. Si solo cambias la lógica del ASM, basta con volver a ejecutar UberASMTool.&lt;br /&gt;
&lt;br /&gt;
Los nombres &amp;lt;code&amp;gt;RAM_LIBRE_...&amp;lt;/code&amp;gt; de los ejemplos son marcadores: reemplázalos por direcciones de RAM libre antes de insertar el código. No son defines de Dynamic Xtreme. Reserva la cantidad de bytes indicada y utiliza direcciones distintas para variables que deban coexistir. Comprueba que no las utilicen el juego, Dynamic Xtreme, Lunar Magic u otros recursos; que una dirección esté libre en SMW original no garantiza que siga libre en tu ROM. Puedes buscar direcciones en el [https://www.smwcentral.net/?p=memorymap&amp;amp;game=smw&amp;amp;u=0&amp;amp;address=&amp;amp;sizeOperation=%3D&amp;amp;sizeValue=&amp;amp;region%5B%5D=ram&amp;amp;type=Empty&amp;amp;description= mapa de RAM de SMW Central filtrado por espacios vacíos].&lt;br /&gt;
&lt;br /&gt;
Si utilizas una dirección corta de RAM de SMW que no pertenece a la &#039;&#039;&#039;Direct Page&#039;&#039;&#039;, añade &amp;lt;code&amp;gt;|!addr&amp;lt;/code&amp;gt; para aplicar el remapeo correspondiente a LoROM o SA-1. Por ejemplo, al elegir la dirección del temporizador:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!AnimationTimer = RAM_LIBRE_ANIM_TIMER|!addr&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sustituye &amp;lt;code&amp;gt;RAM_LIBRE_ANIM_TIMER&amp;lt;/code&amp;gt; por la dirección elegida y conserva &amp;lt;code&amp;gt;|!addr&amp;lt;/code&amp;gt;. Las direcciones de Direct Page se acceden mediante la base D del contexto de ejecución y no utilizan este remapeo. Si eliges una dirección completa de 24 bits, comprueba su banco y que las instrucciones del ejemplo puedan acceder a ella; &amp;lt;code&amp;gt;|!addr&amp;lt;/code&amp;gt; está pensado aquí para las direcciones cortas fuera de Direct Page.&lt;br /&gt;
&lt;br /&gt;
== Reservar paletas para otros recursos ==&lt;br /&gt;
&lt;br /&gt;
Si una animación, un HUD u otro recurso necesita una paleta fija, conviene reservarla para que Dynamic Xtreme no la elija al asignar colores a los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
Para reservarla, escribe &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; en su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt;. Cada entrada ocupa 2 bytes. Por ejemplo, la paleta 9 utiliza el desplazamiento &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;: 9 × 2.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$FFFE&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_ID+$12    ; Reservar la paleta 9&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para reservar varias, escribe el mismo valor en sus entradas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Paleta !! Desplazamiento&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| A || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| B || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| C || &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| D || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| E || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| F || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La reserva impide que la asignación automática reclame esa paleta; no carga colores por sí misma. Un recurso configurado para utilizarla manualmente todavía puede cambiar sus colores, por lo que no debes asignársela también a otro recurso que necesite una paleta diferente.&lt;br /&gt;
&lt;br /&gt;
== Elegir el espacio de VRAM para sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Los sprites dinámicos necesitan una parte de VRAM donde cargar sus poses. Elige un espacio que no estés utilizando para gráficos fijos del nivel.&lt;br /&gt;
&lt;br /&gt;
Puedes consultar el [[SMW_VRAM_Map#Levels|mapa de VRAM de SMW en SNESLab]] para ver qué regiones corresponden a SP1, SP2, SP3 y SP4.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para permitir que utilicen SP4:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si necesitas más espacio y el nivel lo permite, puedes elegir &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; para SP3 y SP4, o &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt; para SP2, SP3 y SP4. Hay más opciones, incluidas medias páginas y configuraciones para compartir espacio con el jugador o DSX.&lt;br /&gt;
&lt;br /&gt;
Los defines disponibles están en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y en la [[es/Dynamic_Xtreme_ASM_API#Configuraciones_de_espacio_para_poses_dinámicas|tabla de configuraciones de la API]]. Configura el espacio antes de que el nivel empiece a cargar poses; cambiarlo no elimina automáticamente las poses que ya estaban en VRAM.&lt;br /&gt;
&lt;br /&gt;
== Configurar la cantidad de datos que se transfieren por frame ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; indica cuántos bytes pueden programar las cargas normales de Dynamic Xtreme durante un frame. Lo comparten las poses dinámicas, las animaciones y las demás transferencias realizadas con sus macros.&lt;br /&gt;
&lt;br /&gt;
El valor predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Este ejemplo lo aumenta a &amp;lt;code&amp;gt;$0A00&amp;lt;/code&amp;gt;, equivalente a 2560 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0A00&lt;br /&gt;
    STA.l DX_Dynamic_MaxDataPerFrame&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Subirlo permite intentar más cargas durante el mismo frame, pero no aumenta el tiempo que tiene SNES para copiarlas. Si la cantidad total es excesiva, pueden aparecer problemas visuales. Ajusta el valor según el nivel y comprueba el resultado con sus sprites y animaciones funcionando juntos.&lt;br /&gt;
&lt;br /&gt;
Las macros normales devuelven el carry desactivado si una carga no cabe en el límite. En ese caso, conserva lo que ya se muestra y vuelve a intentarlo después. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; se saltan la comprobación y también suman sus bytes al total.&lt;br /&gt;
&lt;br /&gt;
== Crear animaciones de gráficos ==&lt;br /&gt;
&lt;br /&gt;
Este ejemplo crea una animación de gráficos: una tabla indica dónde empieza cada imagen, un temporizador controla cuándo cambiarla y la imagen anterior se mantiene si no se acepta la transferencia.&lt;br /&gt;
&lt;br /&gt;
Declara los archivos del ejemplo en &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Aquí pon RAM libre: un byte distinto para cada variable.&lt;br /&gt;
!CurrentPoseIndex = RAM_LIBRE_ANIM_POSE&lt;br /&gt;
!AnimationTimer = RAM_LIBRE_ANIM_TIMER&lt;br /&gt;
!PaletteLoaded = RAM_LIBRE_ANIM_PALETA&lt;br /&gt;
&lt;br /&gt;
; Frames de espera antes de intentar el siguiente cambio.&lt;br /&gt;
!TimePerPose = $03&lt;br /&gt;
&lt;br /&gt;
; Bytes de cada imagen: un tile de 8x8 en 4bpp ocupa $0020.&lt;br /&gt;
!DataSend = $0200&lt;br /&gt;
&lt;br /&gt;
; Cantidad de imágenes utilizadas.&lt;br /&gt;
!NumberOfPoses = $05&lt;br /&gt;
&lt;br /&gt;
; Origen: recurso instalado. También puedes usar !AN2Buffer2.&lt;br /&gt;
!Source = !ResourceSMMArrow&lt;br /&gt;
&lt;br /&gt;
; Dirección de destino en VRAM.&lt;br /&gt;
!Destination = !BG2Line0&lt;br /&gt;
&lt;br /&gt;
; Paleta instalada y primer color de destino.&lt;br /&gt;
!Palette = &amp;quot;SMMArrowPal&amp;quot;&lt;br /&gt;
!PaletteDestination = $71&lt;br /&gt;
&lt;br /&gt;
; 0 = sin efecto global; 1 = recibe el efecto global.&lt;br /&gt;
!PaletteGlobalEffect = 0&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    STZ !CurrentPoseIndex&lt;br /&gt;
    LDA #!TimePerPose&lt;br /&gt;
    STA !AnimationTimer&lt;br /&gt;
    STZ !PaletteLoaded&lt;br /&gt;
&lt;br /&gt;
    %ForcedTransferToVRAM(#!Destination, #!Source, #((!Source&amp;gt;&amp;gt;16)&amp;amp;$FF), #!DataSend)&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteLoaded&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; Reintentar la paleta si no se aceptó durante init.&lt;br /&gt;
    LDA !PaletteLoaded&lt;br /&gt;
    BNE .Animate&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCS .PaletteReady&lt;br /&gt;
    RTL&lt;br /&gt;
.PaletteReady&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteLoaded&lt;br /&gt;
&lt;br /&gt;
.Animate&lt;br /&gt;
    LDA !AnimationTimer&lt;br /&gt;
    BEQ .NextPose&lt;br /&gt;
    DEC !AnimationTimer&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
.NextPose&lt;br /&gt;
    LDA !CurrentPoseIndex&lt;br /&gt;
    INC A&lt;br /&gt;
    CMP #!NumberOfPoses&lt;br /&gt;
    BCC .SelectPose&lt;br /&gt;
    LDA #$00&lt;br /&gt;
.SelectPose&lt;br /&gt;
    STA $05&lt;br /&gt;
    ASL&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l PosesTable,x&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC.w #!Source&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    %TransferToVRAM(#!Destination, $00, #((!Source&amp;gt;&amp;gt;16)&amp;amp;$FF), #!DataSend)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA $05&lt;br /&gt;
    STA !CurrentPoseIndex&lt;br /&gt;
    LDA #!TimePerPose&lt;br /&gt;
    STA !AnimationTimer&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
PosesTable:&lt;br /&gt;
    dw $0000&lt;br /&gt;
    dw !DataSend*$01&lt;br /&gt;
    dw !DataSend*$02&lt;br /&gt;
    dw !DataSend*$03&lt;br /&gt;
    dw !DataSend*$04&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!TimePerPose&amp;lt;/code&amp;gt;: tiempo de espera. Con &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;, el cambio se intenta cada cuatro frames: tres para descontar el temporizador y uno para realizar el cambio.&lt;br /&gt;
* &amp;lt;code&amp;gt;!DataSend&amp;lt;/code&amp;gt;: bytes de cada imagen. &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; equivale a 16 tiles de 8×8 en 4bpp.&lt;br /&gt;
* &amp;lt;code&amp;gt;!NumberOfPoses&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PosesTable&amp;lt;/code&amp;gt;: cantidad de imágenes y sus desplazamientos dentro del origen. El ejemplo utiliza las primeras cinco imágenes de &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;. Si añades más, amplía también la tabla.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Source&amp;lt;/code&amp;gt;: dirección de los gráficos. El ejemplo lee directamente &amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt;; para animar gráficos ya preparados por Lunar Magic puedes usar &amp;lt;code&amp;gt;!AN2Buffer2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Destination&amp;lt;/code&amp;gt;: zona de VRAM que se actualizará. Coloca en el nivel tiles que utilicen esa zona y comprueba que otro recurso no la sobrescriba.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteDestination&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt;: paleta, primer color de destino y participación en el efecto global.&lt;br /&gt;
&lt;br /&gt;
Reemplaza los tres marcadores de RAM del principio por direcciones disponibles durante todo el nivel: cada variable necesita un byte propio. No son scratch temporales. &amp;lt;code&amp;gt;!PaletteLoaded&amp;lt;/code&amp;gt; permite reintentar una carga de paleta rechazada sin repetirla después de que haya sido aceptada.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt; se generan al instalar el DynamicInfo y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres se normalizan en PascalCase eliminando separadores; en este caso se conservan las mayúsculas de &amp;lt;code&amp;gt;SMMArrow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Todas las imágenes utilizadas deben quedar en el mismo banco del origen. La carga inicial de gráficos utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;; los siguientes cambios respetan el límite de datos por frame. Si una carga se rechaza, el código conserva la imagen anterior y vuelve a intentarla en el siguiente frame, sin avanzar el índice ni reiniciar el temporizador.&lt;br /&gt;
&lt;br /&gt;
El temporizador avanza cada vez que se ejecuta &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;. Si quieres detener la animación durante la pausa o cuando se congela la acción, puedes comprobar &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; antes de descontarlo.&lt;br /&gt;
&lt;br /&gt;
== Cambiar paletas durante el juego ==&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; permiten cargar colores y mantener actualizadas las copias que utilizan SMW y Dynamic Xtreme. También se encargan de preparar los efectos de paleta, por lo que no necesitas copiar buffers ni borrar indicadores a mano.&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza &amp;lt;code&amp;gt;SMMArrowPal.bin&amp;lt;/code&amp;gt;, un archivo de 15 colores (&amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes), y cambia los colores 1-F de la paleta 7. El color 0 queda sin modificar.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;, declara los gráficos como recurso general y la paleta en &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ASM del nivel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Aquí pon una RAM libre de un byte.&lt;br /&gt;
!PaletteChangePending = RAM_LIBRE_CAMBIO_PALETA&lt;br /&gt;
&lt;br /&gt;
!Palette = &amp;quot;SMMArrowPal&amp;quot;&lt;br /&gt;
!PaletteDestination = $71&lt;br /&gt;
!PaletteGlobalEffect = 1&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteChangePending&lt;br /&gt;
    ; Continuar con el primer intento de carga.&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA !PaletteChangePending&lt;br /&gt;
    BNE .TryTransfer&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.TryTransfer&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    ; Confirmar el cambio solo si la llamada fue aceptada.&lt;br /&gt;
    STZ !PaletteChangePending&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reemplaza &amp;lt;code&amp;gt;RAM_LIBRE_CAMBIO_PALETA&amp;lt;/code&amp;gt; por una dirección de RAM libre de un byte, disponible durante todo el nivel. &amp;lt;code&amp;gt;!PaletteChangePending&amp;lt;/code&amp;gt; se pone en 1 al solicitar el cambio y solo vuelve a 0 cuando la macro devuelve el carry activado. Si la llamada falla, el cambio queda pendiente y se reintenta en el siguiente frame. Una vez aceptado, no se repite la carga.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt; selecciona el recurso y &amp;lt;code&amp;gt;!PaletteDestination&amp;lt;/code&amp;gt; el primer color de destino. &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt;, utilizado como último parámetro de la macro, elige cómo se carga:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;: prepara los colores originales para que reciban el efecto global antes de mostrarse. También deja la paleta preparada si todavía no has seleccionado un efecto.&lt;br /&gt;
* &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;: carga los colores sin efecto global y excluye esa paleta del efecto. Además actualiza los buffers de SMW, necesarios para evitar problemas de colores durante la animación de victoria del goal.&lt;br /&gt;
&lt;br /&gt;
Para cargar la misma paleta sin efecto global, cambia únicamente este define; conserva la comprobación del carry:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!PaletteGlobalEffect = 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si los efectos están deshabilitados en la instalación, ambas opciones realizan una carga directa. Cuando están habilitados y utilizas &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, el sistema carga el resultado ya procesado; no se muestra primero la paleta sin efecto durante un frame.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; utiliza los defines &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt;, generados desde &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; del DynamicInfo y publicados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra. En este caso se conserva &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; tal como está escrito.&lt;br /&gt;
&lt;br /&gt;
Para solicitar de nuevo el cambio durante el juego, pon &amp;lt;code&amp;gt;!PaletteChangePending&amp;lt;/code&amp;gt; en 1 cuando se cumpla la condición que elijas. No lo hagas cada frame si la paleta no cambia. En una carga directa, el carry activado indica que se programó la transferencia; con efecto global, indica que los colores originales quedaron preparados, no que el resultado ya esté en pantalla.&lt;br /&gt;
&lt;br /&gt;
La opción de efecto se aplica a toda la paleta de 16 colores. Si cargas colores para recibir un efecto global, prepara todos sus colores visibles, como los 15 de este ejemplo; no cambies solo unos pocos esperando conservar una base que todavía no has preparado.&lt;br /&gt;
&lt;br /&gt;
Si eliges una paleta de sprites 8-F para un uso fijo, resérvala primero como se explica al comienzo del artículo. Estas macros no realizan asignación automática. Para cargar desde una dirección, un puntero o una tabla, consulta [[es/Dynamic_Xtreme_ASM_API#Cargar_colores_con_TransferPalette|Cargar colores con TransferPalette en la API]].&lt;br /&gt;
&lt;br /&gt;
== Cambiar los gráficos del jugador ==&lt;br /&gt;
&lt;br /&gt;
Este ejemplo alterna entre el jugador original y Geno al pulsar arriba. Sus defines permiten elegir los gráficos y las cuatro paletas: Mario, Luigi, Mario con fuego y Luigi con fuego. También vuelve a seleccionar la paleta cuando cambia el estado del jugador.&lt;br /&gt;
&lt;br /&gt;
Necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; habilitado. Los gráficos personalizados deben utilizar la misma organización de poses que los originales; cambiar el origen no adapta un spritesheet de otro formato.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/Geno.dynamicinfo&amp;lt;/code&amp;gt;, declara:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    Geno.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    GenoPal.bin&lt;br /&gt;
    GenoPalPlayer2.bin&lt;br /&gt;
    FireGenoPal.bin&lt;br /&gt;
    FireGenoPalPlayer2.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/Geno.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Aquí pon una RAM libre de dos bytes consecutivos.&lt;br /&gt;
!Last0D82 = RAM_LIBRE_JUGADOR_2_BYTES&lt;br /&gt;
&lt;br /&gt;
; Gráficos del jugador personalizado.&lt;br /&gt;
!PlayerGFXResource = !ResourceGeno&lt;br /&gt;
&lt;br /&gt;
; Paletas: jugador 1, jugador 2 y sus variantes con fuego.&lt;br /&gt;
!PlayerGFXPalette = !PaletteGenoPal&lt;br /&gt;
!PlayerGFXPalettePlayer2 = !PaletteGenoPalPlayer2&lt;br /&gt;
!PlayerGFXFirePalette = !PaletteFireGenoPal&lt;br /&gt;
!PlayerGFXFirePalettePlayer2 = !PaletteFireGenoPalPlayer2&lt;br /&gt;
&lt;br /&gt;
; Botón de cambio: $08 = arriba.&lt;br /&gt;
!ChangeButton = $08&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA !Last0D82&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA !ButtonDown_BYETUDLR&lt;br /&gt;
    AND #!ChangeButton&lt;br /&gt;
    BNE .Change&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    CMP !Last0D82&lt;br /&gt;
    BNE .Reload&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
.Change&lt;br /&gt;
    LDA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    CMP.b #!GFX32Buffer&amp;gt;&amp;gt;16&lt;br /&gt;
    BEQ .ChooseGeno&lt;br /&gt;
    JMP .Mario&lt;br /&gt;
.ChooseGeno&lt;br /&gt;
    JMP .Geno&lt;br /&gt;
&lt;br /&gt;
.Reload&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    CMP.b #!GFX32Buffer&amp;gt;&amp;gt;16&lt;br /&gt;
    BNE .Geno&lt;br /&gt;
    JMP .Mario&lt;br /&gt;
&lt;br /&gt;
.Geno&lt;br /&gt;
    ; Obtener 0, 1, 2 o 3 según jugador y estado de fuego.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    SEC&lt;br /&gt;
    SBC #!PlayerBasePalette&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    %DivW($01, $00, #$14)&lt;br /&gt;
&lt;br /&gt;
    ; Cada dirección de GenoPals ocupa tres bytes.&lt;br /&gt;
    LDA !DivisionResult&lt;br /&gt;
    ASL&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC !DivisionResult&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    ; Conservar el origen elegido y preparar los colores 2-5.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l GenoPals,x&lt;br /&gt;
    STA $03&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$0002&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.l GenoPals+2,x&lt;br /&gt;
    STA $02&lt;br /&gt;
    STA $05&lt;br /&gt;
&lt;br /&gt;
    %TransferPaletteFromPointer($00, #$82, $0008, 0)&lt;br /&gt;
    BCS .ApplyGeno&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.ApplyGeno&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!PlayerGFXResource&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!PlayerGFXResource&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
&lt;br /&gt;
    ; La rutina del jugador carga los colores 6-F.&lt;br /&gt;
    LDA $03&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$000A&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA $05&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    JMP .ConfirmSelection&lt;br /&gt;
&lt;br /&gt;
.Mario&lt;br /&gt;
    %TransferPaletteFromAddress(!PlayerPaletteColor2To5, #$82, $0008, 0)&lt;br /&gt;
    BCS .ApplyMario&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.ApplyMario&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!GFX32Buffer&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    LDA.w #(!GFX32Buffer&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
.ConfirmSelection&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA !Last0D82&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
GenoPals:&lt;br /&gt;
    dl !PlayerGFXPalette&lt;br /&gt;
    dl !PlayerGFXPalettePlayer2&lt;br /&gt;
    dl !PlayerGFXFirePalette&lt;br /&gt;
    dl !PlayerGFXFirePalettePlayer2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!PlayerGFXResource&amp;lt;/code&amp;gt;: gráficos del personaje personalizado.&lt;br /&gt;
* Los cuatro defines &amp;lt;code&amp;gt;!PlayerGFX...Palette...&amp;lt;/code&amp;gt;: direcciones de sus paletas, en el orden de la tabla &amp;lt;code&amp;gt;GenoPals&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ChangeButton&amp;lt;/code&amp;gt;: botón que alterna entre los personajes. Utiliza los bits del control &amp;lt;code&amp;gt;BYETUDLR&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; corresponde a arriba.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Last0D82&amp;lt;/code&amp;gt;: reemplaza &amp;lt;code&amp;gt;RAM_LIBRE_JUGADOR_2_BYTES&amp;lt;/code&amp;gt; por una dirección de RAM libre con dos bytes consecutivos disponibles. Guarda la selección de paleta del juego; ninguno de esos bytes debe estar ocupado por otro código.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGeno&amp;lt;/code&amp;gt; y los defines &amp;lt;code&amp;gt;!PaletteGenoPal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteGenoPalPlayer2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteFireGenoPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteFireGenoPalPlayer2&amp;lt;/code&amp;gt; se generan desde el DynamicInfo y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres usan PascalCase eliminando espacios, guiones y guiones bajos, y conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
Cada archivo de paleta contiene los colores 1-F. Se omite su primer color para copiar los colores 2-5; los últimos diez comienzan en &amp;lt;code&amp;gt;+$0A&amp;lt;/code&amp;gt; y los utiliza la rutina del jugador.&lt;br /&gt;
&lt;br /&gt;
Las cargas de los colores 2-5 utilizan &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, que también actualiza los buffers de SMW. El ejemplo no confirma el cambio de gráficos si esa transferencia es rechazada. Un cambio pendiente por el estado del jugador se vuelve a intentar mientras no coincida con &amp;lt;code&amp;gt;!Last0D82&amp;lt;/code&amp;gt;; si se rechaza un cambio solicitado con el botón, vuelve a pulsarlo.&lt;br /&gt;
&lt;br /&gt;
El código distingue al jugador original por el banco de &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt;. Si lo adaptas para alternar entre varios personajes personalizados en ROM, necesitarás otra forma de recordar cuál está seleccionado.&lt;br /&gt;
&lt;br /&gt;
Este ejemplo carga la paleta del jugador sin efecto global. No basta con cambiar a &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; el parámetro de una carga de cuatro colores para añadirle un efecto: en ese caso hay que preparar todos los colores visibles de la paleta 8 y respetar su carga especial.&lt;br /&gt;
&lt;br /&gt;
== Aplicar un efecto global de paleta ==&lt;br /&gt;
&lt;br /&gt;
Los siguientes ejemplos permiten aplicar un efecto fijo, recorrer efectos en un ciclo o realizar una transición que se detiene al terminar. Puedes elegir cada paleta por separado e incluir el color fijo. Los códigos de ciclo y transición también permiten configurar la velocidad con &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
En los archivos &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; selecciona el tipo de efecto. Los ratios utilizan valores de 0 a 127 y los valores &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt;, de 0 a 31.&lt;br /&gt;
&lt;br /&gt;
=== Elegir las paletas afectadas ===&lt;br /&gt;
&lt;br /&gt;
En cada código, cambia &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt; a 1 para incluir la paleta correspondiente o a 0 para excluirla. &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; controla el color fijo y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt; permite incluir también el color 0,0.&lt;br /&gt;
&lt;br /&gt;
Las máscaras &amp;lt;code&amp;gt;!EnableBG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableSP&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColors&amp;lt;/code&amp;gt; se calculan a partir de esos ajustes. No necesitas modificarlas a mano. En la API actual, el bit bajo corresponde a la primera paleta de cada grupo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor del bit !! Paleta de fondo !! Paleta de sprites&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || 0 || 8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || 1 || 9&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || 2 || A&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || 3 || B&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || 4 || C&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || 5 || D&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || 6 || E&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; || 7 || F&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
El color fijo y el color 0,0 utilizan &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt;: bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; y bit &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, respectivamente.&lt;br /&gt;
&lt;br /&gt;
En sprites con asignación dinámica, configura también el bit E de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;. Si cargas paletas mediante &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, su último parámetro determina si esas paletas participan en el efecto global. Evita que otro código vuelva a escribir máscaras distintas sin tener en cuenta esa configuración.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto fijo ===&lt;br /&gt;
&lt;br /&gt;
Este ejemplo aplica el efecto que indiques en &amp;lt;code&amp;gt;!PaletteEffetID&amp;lt;/code&amp;gt;. La configuración mostrada habilita todas las paletas y el color fijo, y selecciona el último efecto de &amp;lt;code&amp;gt;DecreaseSaturation&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Guarda el siguiente contenido en &amp;lt;code&amp;gt;DynamicXtreme/DecreaseSaturation.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 4, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 8, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 12, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 16, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 20, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 25, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 29, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 33, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 37, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 41, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 45, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 49, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 53, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 57, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 61, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 66, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 70, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 74, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 78, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 82, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 86, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 90, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 94, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 98, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 102, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 107, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 111, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 115, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 119, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 123, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 11}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El archivo define 32 efectos. &amp;lt;code&amp;gt;EffectType = 11&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;Channel2 = 0&amp;lt;/code&amp;gt; indica que se reduce la saturación y &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; controla cuánto. El último efecto utiliza 127, que aplica el cambio completo.&lt;br /&gt;
&lt;br /&gt;
El código ASM es:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/DecreaseSaturation.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 1&lt;br /&gt;
!P2 = 1&lt;br /&gt;
!P3 = 1&lt;br /&gt;
!P4 = 1&lt;br /&gt;
!P5 = 1&lt;br /&gt;
!P6 = 1&lt;br /&gt;
!P7 = 1&lt;br /&gt;
&lt;br /&gt;
!P8 = 1&lt;br /&gt;
!P9 = 1&lt;br /&gt;
!PA = 1&lt;br /&gt;
!PB = 1&lt;br /&gt;
!PC = 1&lt;br /&gt;
!PD = 1&lt;br /&gt;
!PE = 1&lt;br /&gt;
!PF = 1&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Efecto que se aplica al entrar al nivel.&lt;br /&gt;
!PaletteEffetID = !PaletteEffectIDDecreaseSaturation31&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;: paletas afectadas.&lt;br /&gt;
* &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: participación de esos colores.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteEffetID&amp;lt;/code&amp;gt;: efecto seleccionado. Puedes utilizar cualquier ID generado desde tu archivo de efectos, no solo el último de este ejemplo.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation31&amp;lt;/code&amp;gt; se generan desde el &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando espacios, guiones y guiones bajos, y conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
La selección se realiza en &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;; no hace falta repetirla cada frame. Para quitar el efecto, escribe 0 en el ID global y deja las paletas habilitadas para que el sistema restaure sus colores originales:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hacer que el efecto se repita en un ciclo ===&lt;br /&gt;
&lt;br /&gt;
Este ejemplo recorre una secuencia de efectos y vuelve al primero. Puedes configurar la velocidad, el primer y último ID y las paletas afectadas. La configuración mostrada incluye solo la paleta 0 y el color fijo.&lt;br /&gt;
&lt;br /&gt;
Guarda el siguiente contenido en &amp;lt;code&amp;gt;DynamicXtreme/Hue.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 1, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 2, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 3, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 4, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 5, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 6, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 7, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 8, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 9, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 10, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 11, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 12, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 13, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 14, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 15, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 16, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 17, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 18, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 19, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 20, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 21, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 22, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 23, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 24, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 25, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 26, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 27, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 28, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 29, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 30, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 31, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 31, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El archivo define 32 efectos de tono. &amp;lt;code&amp;gt;EffectType = 9&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio1 = 127&amp;lt;/code&amp;gt; aplica por completo el tono seleccionado.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Hue.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 0&lt;br /&gt;
!P2 = 0&lt;br /&gt;
!P3 = 0&lt;br /&gt;
!P4 = 0&lt;br /&gt;
!P5 = 0&lt;br /&gt;
!P6 = 0&lt;br /&gt;
!P7 = 0&lt;br /&gt;
&lt;br /&gt;
!P8 = 0&lt;br /&gt;
!P9 = 0&lt;br /&gt;
!PA = 0&lt;br /&gt;
!PB = 0&lt;br /&gt;
!PC = 0&lt;br /&gt;
!PD = 0&lt;br /&gt;
!PE = 0&lt;br /&gt;
!PF = 0&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Valores permitidos: $00, $01, $03, $07, $0F, $1F, $3F, $7F y $FF.&lt;br /&gt;
!Delay = $03&lt;br /&gt;
&lt;br /&gt;
!StartingPaletteEffetID = !PaletteEffectIDHue0&lt;br /&gt;
!EndPaletteEffetID = !PaletteEffectIDHue31&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #!Delay&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!EndPaletteEffetID&lt;br /&gt;
    BCS .Restart&lt;br /&gt;
    INC A&lt;br /&gt;
    BRA .Store&lt;br /&gt;
.Restart&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
.Store&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: colores afectados.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;: separación entre cambios. &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; cambia cada frame, &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; cada dos, &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; cada cuatro y &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; cada ocho. Utiliza únicamente los valores indicados en el comentario.&lt;br /&gt;
* &amp;lt;code&amp;gt;!StartingPaletteEffetID&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EndPaletteEffetID&amp;lt;/code&amp;gt;: primer y último efecto del ciclo. Deben pertenecer a una secuencia de IDs consecutivos, con el inicio menor o igual que el final.&lt;br /&gt;
&lt;br /&gt;
El ciclo muestra el último ID antes de volver al primero. Utiliza &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; para marcar el momento de los cambios; por ello, el primer intervalo depende del valor que tenga ese contador al entrar al nivel. Si quieres detenerlo al congelarse la acción, comprueba también &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt; al comienzo de &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDHue0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDHue31&amp;lt;/code&amp;gt; se generan desde el &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores; en este caso conserva &amp;lt;code&amp;gt;Hue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Hacer una transición que se detiene al terminar ===&lt;br /&gt;
&lt;br /&gt;
Este ejemplo avanza desde el efecto inicial hasta el final y mantiene ese último resultado. Puedes configurar las paletas afectadas, el color fijo, la velocidad y el rango de IDs.&lt;br /&gt;
&lt;br /&gt;
Guarda el siguiente contenido en &amp;lt;code&amp;gt;DynamicXtreme/Night.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 0, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 4, &amp;quot;Ratio2&amp;quot;: 4, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 8, &amp;quot;Ratio2&amp;quot;: 8, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 12, &amp;quot;Ratio2&amp;quot;: 12, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 16, &amp;quot;Ratio2&amp;quot;: 16, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 20, &amp;quot;Ratio2&amp;quot;: 20, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 25, &amp;quot;Ratio2&amp;quot;: 25, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 29, &amp;quot;Ratio2&amp;quot;: 29, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 33, &amp;quot;Ratio2&amp;quot;: 33, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 37, &amp;quot;Ratio2&amp;quot;: 37, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 41, &amp;quot;Ratio2&amp;quot;: 41, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 45, &amp;quot;Ratio2&amp;quot;: 45, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 49, &amp;quot;Ratio2&amp;quot;: 49, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 53, &amp;quot;Ratio2&amp;quot;: 53, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 57, &amp;quot;Ratio2&amp;quot;: 57, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 61, &amp;quot;Ratio2&amp;quot;: 61, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 66, &amp;quot;Ratio2&amp;quot;: 66, &amp;quot;EffectType&amp;quot;: 2}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La transición tiene 17 pasos. &amp;lt;code&amp;gt;EffectType = 2&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixRG&amp;lt;/code&amp;gt;: reduce el rojo y el verde sin modificar el azul. Los ratios aumentan de 0 a 66 para oscurecer los colores gradualmente sin eliminar por completo el rojo y el verde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Night.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 1&lt;br /&gt;
!P2 = 1&lt;br /&gt;
!P3 = 1&lt;br /&gt;
!P4 = 1&lt;br /&gt;
!P5 = 1&lt;br /&gt;
!P6 = 1&lt;br /&gt;
!P7 = 1&lt;br /&gt;
&lt;br /&gt;
!P8 = 1&lt;br /&gt;
!P9 = 1&lt;br /&gt;
!PA = 1&lt;br /&gt;
!PB = 1&lt;br /&gt;
!PC = 1&lt;br /&gt;
!PD = 1&lt;br /&gt;
!PE = 1&lt;br /&gt;
!PF = 1&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Valores permitidos: $00, $01, $03, $07, $0F, $1F, $3F, $7F y $FF.&lt;br /&gt;
!Delay = $03&lt;br /&gt;
&lt;br /&gt;
!StartingPaletteEffetID = !PaletteEffectIDNight0&lt;br /&gt;
!EndPaletteEffetID = !PaletteEffectIDNight16&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #!Delay&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!EndPaletteEffetID&lt;br /&gt;
    BCS .Finished&lt;br /&gt;
    INC A&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
.Finished&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: colores afectados.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;: tiempo entre cambios, con los mismos valores permitidos en el ejemplo de ciclo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!StartingPaletteEffetID&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EndPaletteEffetID&amp;lt;/code&amp;gt;: primer y último efecto. Deben ser IDs consecutivos en orden ascendente.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDNight16&amp;lt;/code&amp;gt; se generan desde &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres usan PascalCase eliminando separadores; aquí se conserva &amp;lt;code&amp;gt;Night&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Este ejemplo cambia entre efectos de mezcla. Para una transición hacia otra paleta completa, utiliza &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt;, explicados en [[es/Dynamic_Xtreme_files_and_formats#Transiciones_de_paleta|Archivos y formatos]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_ASM_API&amp;diff=21385</id>
		<title>es/Dynamic Xtreme ASM API</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_ASM_API&amp;diff=21385"/>
		<updated>2026-10-25T17:36:52Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_ASM_API}}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Para aprender a organizar un sprite completo, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites]].&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades necesarias para utilizar la API ==&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Rutinas y macros que permite utilizar !! Dependencias y detalles&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;&lt;br /&gt;
| [[#PPU|Transferencias a VRAM]]: &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt; y sus variantes &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WithLenght&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Proporciona las cargas de gráficos. También es necesaria para &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;&lt;br /&gt;
| [[#DefineDynamicSpaceConfig|DefineDynamicSpaceConfig]], [[#DynamicPoseSpaceConfig|DynamicPoseSpaceConfig]], [[#TakeDynamicRequest|TakeDynamicRequest]], [[#DynamicRoutine|DynamicRoutine]], &amp;lt;code&amp;gt;SetPropertyAndOffset&amp;lt;/code&amp;gt;, [[#Upload|!Upload]], &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; y las macros generales &amp;lt;code&amp;gt;GeneralUpload&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Upload&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;StandardSpriteUpload&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Requiere &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;. Para dibujar las poses obtenidas también necesitas &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;&lt;br /&gt;
| [[#DXDraw|!DXDraw]], &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; y las macros generales &amp;lt;code&amp;gt;Draw&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;StandardSpriteDraw&amp;lt;/code&amp;gt; y [[#DrawStatic|DrawStatic]]. Incluye las rutinas de dibujo y comprobación de tiles que utiliza el sistema.&lt;br /&gt;
| El dibujo de poses dinámicas también requiere &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;DrawStatic&amp;lt;/code&amp;gt; puede dibujar poses estáticas sin habilitar el sistema de poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;AssignPalette&amp;lt;/code&amp;gt;, [[#PaletteAssignment|!PaletteAssignment]], &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt; y sus macros generales; &amp;lt;code&amp;gt;LoadPaletteIDAndAddress&amp;lt;/code&amp;gt;; las macros [[#Cargar colores con TransferPalette|TransferPalette]] y las [[#PPU|transferencias a CGRAM]].&lt;br /&gt;
| Proporciona la asignación y carga de paletas. Para aplicar efectos también debes habilitar &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;&lt;br /&gt;
| [[#Efectos de paleta|SetRGBBase, SetHSLBase, Mix, MixAndMerge, PaletteTransition, DoEffect y conversiones RGB/HSL]], con sus variantes. También permite utilizar &amp;lt;code&amp;gt;ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt;, como aliases de sprites o macros generales.&lt;br /&gt;
| Requiere &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;. Permite aplicar el efecto global mediante la asignación de paletas o &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;&lt;br /&gt;
| Permite personalizar los gráficos y las paletas del jugador mediante las [[#Jugador y Yoshi|variables del jugador]]. No añade una familia de llamadas propia a las categorías anteriores.&lt;br /&gt;
| Requiere &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;&lt;br /&gt;
| Permite personalizar los gráficos de Yoshi mediante las [[#Jugador y Yoshi|variables de Yoshi]].&lt;br /&gt;
| Requiere &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, junto con sus dependencias.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;&lt;br /&gt;
| No añade llamadas a esta API.&lt;br /&gt;
| 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
| No añaden familias de llamadas a esta API.&lt;br /&gt;
| Modifican el funcionamiento interno de sus respectivos sistemas. No necesitas habilitarlas para obtener las macros de poses, dibujo, paletas o matemáticas.&lt;br /&gt;
|-&lt;br /&gt;
| Sin una funcionalidad adicional&lt;br /&gt;
| [[#Matemáticas|Mul, Div y sus variantes W y After...]].&lt;br /&gt;
| Las macros de matemáticas se incluyen desde &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; independientemente de las opciones anteriores.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las macros de PPU se incluyen si está habilitado &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;, pero utiliza las de VRAM con &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; y las de CGRAM con &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;. Que Asar reconozca el nombre de una macro no significa que estén habilitadas las listas y variables que esa macro necesita.&lt;br /&gt;
&lt;br /&gt;
Para cargar &#039;&#039;&#039;y dibujar&#039;&#039;&#039; poses dinámicas, habilita &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;. Si el sprite también carga paletas, añade &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;; si utiliza efectos, añade &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Integración con las herramientas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Contexto !! Archivos y llamadas&lt;br /&gt;
|-&lt;br /&gt;
| PIXI&lt;br /&gt;
| La instalación copia los defines generales a &amp;lt;code&amp;gt;asm/ExtraDefines&amp;lt;/code&amp;gt; y las rutinas compartidas a &amp;lt;code&amp;gt;routines&amp;lt;/code&amp;gt;. Para los aliases de sprites, incluye &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt;, según corresponda. Las diferencias entre tipos se indican en cada llamada.&lt;br /&gt;
|-&lt;br /&gt;
| UberASMTool&lt;br /&gt;
| La instalación enlaza &amp;lt;code&amp;gt;ExtraDefines/DXDefines.asm&amp;lt;/code&amp;gt; desde &amp;lt;code&amp;gt;other/macro_library.asm&amp;lt;/code&amp;gt;. Utiliza las macros generales y las rutinas del parche con sus parámetros; los aliases como &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; pertenecen a los archivos de defines para sprites de PIXI.&lt;br /&gt;
|-&lt;br /&gt;
| GPS&lt;br /&gt;
| La instalación enlaza &amp;lt;code&amp;gt;ExtraDefines/DXDefines.asm&amp;lt;/code&amp;gt; desde &amp;lt;code&amp;gt;defines.asm&amp;lt;/code&amp;gt;. Utiliza las macros generales y las rutinas del parche, preparando sus entradas desde el código del bloque.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. 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 [[es/Dynamic_Xtreme_Quick_Start|guía de inicio rápido]].&lt;br /&gt;
&lt;br /&gt;
== Variables y defines ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Los nombres de variables generales comienzan con &amp;lt;code&amp;gt;DX_&amp;lt;/code&amp;gt; y se escriben sin &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt;, por ejemplo &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;. Los defines como &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; sí llevan &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt;. Conserva la escritura exacta del nombre que aparece en el archivo.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Variables generales ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Contadores y cantidad de datos por frame ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; || 2 bytes || Cantidad de bytes que ya se programaron para transferir durante el frame actual. La actualizan las rutinas de carga.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; || 2 bytes || Límite de bytes que las cargas normales pueden programar en un frame. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; pueden superarlo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Poses cargadas en VRAM ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 byte || Cantidad de poses registradas actualmente en la caché.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 valores de 1 byte || Ayuda a encontrar las poses por su ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 128 valores de 2 bytes || ID de cada pose registrada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 128 valores de 2 bytes || Valor de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; de la última vez que se utilizó cada pose. Evita reemplazar gráficos que todavía se están mostrando.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 bytes compartidos || Describen las partes libres u ocupadas de VRAM. Son dos nombres para el mismo espacio de memoria.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 valores de 1 byte || Ayuda al sistema a recorrer las partes libres y ocupadas de VRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Paletas y efecto global ====&lt;br /&gt;
&lt;br /&gt;
Las tablas de 16 paletas utilizan el orden 0-F. En las tablas de valores de 2 bytes, la paleta 1 comienza en &amp;lt;code&amp;gt;+2&amp;lt;/code&amp;gt;, la 2 en &amp;lt;code&amp;gt;+4&amp;lt;/code&amp;gt;, y así sucesivamente.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 byte || Cada bit indica si una de las paletas 0-7 recibe el efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 byte || Cada bit indica si una de las paletas de sprites 8-F recibe el efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || ID del efecto global que se quiere aplicar. El valor 0 indica que no se aplica un efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Último efecto global revisado por el sistema. Se utiliza para detectar cambios.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 16 valores de 2 bytes || Último efecto global calculado para cada paleta. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; significa que aún no hay un resultado; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt;, que hay una actualización pendiente y se conserva el resultado anterior.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 16 valores de 2 bytes || ID asociado a cada paleta. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica que está libre; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; la excluye de la selección automática.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_Updated&amp;lt;/code&amp;gt; || 16 valores de 1 byte || Indica cuáles paletas ya se actualizaron durante el frame. Uso interno.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 byte || Registra qué paletas de sprites se utilizan con efectos. Uso interno del manejo de paletas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para reservar una paleta de sprites y evitar que la selección automática la utilice, su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; debe contener &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt;. Haz la reserva antes de que los sprites comiencen a solicitar paletas.&lt;br /&gt;
&lt;br /&gt;
==== Copias de colores y resultados de efectos ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 bytes || Copia de trabajo de las 256 entradas de color, con 2 bytes por color. Es la fuente de las variantes &amp;lt;code&amp;gt;SetRGBBaseDefault&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SetHSLBaseDefault&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 bytes || Colores originales separados en rojo, verde y azul: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 bytes || Colores originales separados en tono, saturación y luminosidad: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LocalEffectBuffer&amp;lt;/code&amp;gt; || 768 bytes || Espacio de trabajo para el resultado de un efecto local antes de combinarlo con el global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LocalEffectID&amp;lt;/code&amp;gt; || 16 valores de 2 bytes || ID del efecto local aplicado a cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 bytes || Colores resultantes en formato de SNES, con 2 bytes por color. Las variantes &amp;lt;code&amp;gt;AndMergeDefault&amp;lt;/code&amp;gt; escriben aquí.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Cada bit indica si ya se preparó la base RGB de una paleta de fondo o de sprites.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Lo mismo para las bases HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Cada bit indica si ya hay un resultado del efecto para esa paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LastPlayerPal&amp;lt;/code&amp;gt; || 2 bytes || Dirección de la última paleta del jugador procesada. El sistema la compara para detectar cambios.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Color fijo y primer color de la paleta ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 byte || Activa la participación en el efecto global: bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; para el color fijo y bit &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; para el color 0,0. &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; permite ambos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_BaseLoaded&amp;lt;/code&amp;gt; || 1 byte || Indica si se guardaron sus colores originales. Utiliza un bit por destino: &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_RGBBaseLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_ColorEffect_HSLBaseLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Indican si sus colores ya se prepararon en RGB o HSL, con los mismos bits.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Mirror&amp;lt;/code&amp;gt; || 2 bytes || Copia del color fijo que utiliza la actualización habitual del juego.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Base&amp;lt;/code&amp;gt; || 2 bytes || Color fijo original, antes de los efectos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_RGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_FixedColor_HSLBase&amp;lt;/code&amp;gt; || 3 bytes cada una || Color fijo original separado en RGB o HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Result&amp;lt;/code&amp;gt; || 2 bytes || Color fijo calculado después del efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Último efecto global calculado para el color fijo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Base&amp;lt;/code&amp;gt; || 2 bytes || Color 0,0 original.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_RGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_HSLBase&amp;lt;/code&amp;gt; || 3 bytes cada una || Color 0,0 original separado en RGB o HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Result&amp;lt;/code&amp;gt; || 2 bytes || Color 0,0 que se quiere mostrar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Último efecto global calculado para el color 0,0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Update&amp;lt;/code&amp;gt; || 1 byte || Un valor distinto de 0 solicita copiar &amp;lt;code&amp;gt;Result&amp;lt;/code&amp;gt; al color 0,0 durante NMI. Después de copiarlo, el sistema vuelve a poner esta variable en 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Transferencias pendientes ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || Cantidad de copias de gráficos pendientes, en 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || Cantidad de bytes de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || Destino de cada copia en VRAM, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || Dirección de origen de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || Banco de origen de cada copia. La tabla reserva 2 bytes por entrada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || Cantidad de copias de colores pendientes, en 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || Cantidad de bytes de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || Primer color de destino de cada copia, en valores de 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || Dirección de origen de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || Banco de origen de cada copia.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Jugador y Yoshi ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_Enable&amp;lt;/code&amp;gt; || 1 byte || 0 desactiva la carga de gráficos mediante este sistema; un valor distinto de 0 la activa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_Addr&amp;lt;/code&amp;gt; || 2 bytes || Dirección de inicio de los gráficos del jugador dentro del banco indicado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_BNK&amp;lt;/code&amp;gt; || 2 bytes reservados || Banco de origen de los gráficos del jugador. El banco se indica en el byte bajo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_Enable&amp;lt;/code&amp;gt; || 1 byte || 0 desactiva el manejo de paleta del jugador mediante este sistema; un valor distinto de 0 lo activa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_Addr&amp;lt;/code&amp;gt; || 2 bytes || Dirección de origen de la paleta del jugador.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_BNK&amp;lt;/code&amp;gt; || 1 byte || Banco de la paleta. Cuando es 0, la rutina toma la dirección de paleta que utiliza el juego.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_CustomPlayer&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_Dynamic_Player_LastCustomPlayer&amp;lt;/code&amp;gt; || 1 byte cada una || Variables reservadas para identificar al jugador personalizado y el anterior. La inicialización las pone en 0 y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;; actualmente no seleccionan por sí solas los gráficos de un personaje.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_VRAMEnable&amp;lt;/code&amp;gt; || 1 byte || 0 desactiva la carga de gráficos de Yoshi mediante este sistema; un valor distinto de 0 la activa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_Addr&amp;lt;/code&amp;gt; || 2 bytes || Dirección de inicio de los gráficos de Yoshi dentro de su banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_BNK&amp;lt;/code&amp;gt; || 1 byte || Banco de origen de los gráficos de Yoshi.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Dibujo y variables de sprites ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Drawing_InitialIndexHighPriority&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_Drawing_InitialIndexLowPriority&amp;lt;/code&amp;gt; ocupan 1 byte cada una y llevan la cuenta de las posiciones disponibles para dibujar sprites de prioridad alta o baja. &amp;lt;code&amp;gt;DX_Drawing_OAMMap&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Las variables individuales de sprites se definen en &amp;lt;code&amp;gt;DynamicXSpritesTables.asm&amp;lt;/code&amp;gt;. Los archivos &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; permiten utilizar los mismos nombres para los tres tipos:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Nombre para el sprite !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt; || Pose que se quiere mostrar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt; || Última pose que se consiguió y puede dibujarse. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; || Entrada donde el sistema tiene registrada la ubicación de sus gráficos. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt; || Volteo general, volteo adicional de la pose y volteo que se utiliza para dibujar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; || Paleta asignada: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; para la 8, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; para la 9, y así hasta &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; para la F. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; cuando se utiliza asignación dinámica.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; || Opciones &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: efecto global y elección de paleta o grupo de paletas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; || Modo de asignación: automático, manual o manual sin cargar colores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt; || Variante del sprite y última variante procesada al manejar su paleta. &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt; se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen,x&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SafeFrameLowByte,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!SafeFrameHighByte,x&amp;lt;/code&amp;gt; || Último frame en que se intentó solicitar una pose, para evitar repetir el trabajo durante el mismo frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AnimationIndex,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AnimationPoseIndex,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AnimationTimer,x&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!State,x&amp;lt;/code&amp;gt; || Variable para el estado o comportamiento del recurso.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada variable de esta tabla ocupa 1 byte por sprite. Hay &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; entradas para normales, 20 para cluster y 10 para extended. No utilices &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; como cantidad de entradas de cluster o extended.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Defines fijos ===&lt;br /&gt;
&lt;br /&gt;
Estos nombres representan configuraciones y direcciones conocidas. No son variables que cambian durante el juego.&lt;br /&gt;
&lt;br /&gt;
==== Compatibilidad con LoROM y SA-1 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; detecta el tipo de ROM y elige los valores correspondientes. Utiliza estos nombres para que tu código funcione en ambos casos.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! LoROM !! SA-1 !! Uso&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!sa1&amp;lt;/code&amp;gt; || 0 || 1 || Permite elegir código distinto según el tipo de ROM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!dp&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3000&amp;lt;/code&amp;gt; || Ajuste de las direcciones de página directa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!addr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; || Ajuste de las direcciones RAM que lo requieren, por ejemplo &amp;lt;code&amp;gt;$0100|!addr&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!rom&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$800000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$000000&amp;lt;/code&amp;gt; || Ajuste utilizado al acceder a direcciones del código original del juego.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; (12) || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; (22) || Cantidad de posiciones de sprites normales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MultiplicationResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4216&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2306&amp;lt;/code&amp;gt; || Dirección donde se lee el resultado de una multiplicación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DivisionResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4214&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2306&amp;lt;/code&amp;gt; || Dirección donde se lee el cociente de una división.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RemainderResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4216&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2308&amp;lt;/code&amp;gt; || Dirección donde se lee el resto de una división.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Otros defines utilizados para colocar las variables son &amp;lt;code&amp;gt;!normalBnk&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalCopyBNK&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt;. Normalmente basta con utilizar el nombre de cada variable &amp;lt;code&amp;gt;DX_...&amp;lt;/code&amp;gt;, sin calcular su dirección a partir de estos valores.&lt;br /&gt;
&lt;br /&gt;
==== Direcciones de gráficos en VRAM ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia !! Línea 0 !! Avance por línea !! Ejemplo&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG1LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG1Line1 = $0100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG2LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG2Line1 = $0900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG1LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG1Line1 = $1100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG3LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG3Line1 = $1900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG2LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG2Line1 = $2100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG3LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG3Line1 = $2900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LG1LineN&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!LG4LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4400&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4800&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4C00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!LG1Line1 = $4080&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SP1LineN&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!SP4LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6800&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$7000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$7800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!SP4Line1 = $7900&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Layer1Tilemap = $3000&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Layer2Tilemap = $3800&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
==== Configuraciones de espacio para poses dinámicas ====&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt; se entregan a &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt;. El nombre indica qué áreas de gráficos se permiten utilizar. &amp;lt;code&amp;gt;FirstHalf&amp;lt;/code&amp;gt; significa primera mitad y &amp;lt;code&amp;gt;SecondHalf&amp;lt;/code&amp;gt;, segunda mitad. Los nombres con &amp;lt;code&amp;gt;WithPlayer&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;WithDSX&amp;lt;/code&amp;gt; corresponden a las configuraciones previstas para esos casos.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Define&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$09&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP1WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP11WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3ndSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2andSP34&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$11&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$13&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$15&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3ndSP4WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$17&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2andSP34WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$19&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithPlayerAndDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithPlayerAndDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres de esta tabla se escriben exactamente como aparecen en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, incluidos nombres como &amp;lt;code&amp;gt;SecondHalfSSP4&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SP11WithPlayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Otras constantes ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! Valor o uso&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AN2Buffer1&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AN2Buffer2&amp;lt;/code&amp;gt; || Direcciones &amp;lt;code&amp;gt;$7EC100&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$7EAD00&amp;lt;/code&amp;gt; utilizadas para datos de animación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt;, dirección del buffer habitual de GFX32.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PlayerPaletteColor2To5&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$00B280&amp;lt;/code&amp;gt;, datos de los colores 2-5 de la paleta del jugador.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PlayerBasePalette&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$00B2C8&amp;lt;/code&amp;gt;, datos de la paleta base del jugador.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las opciones de instalación, como &amp;lt;code&amp;gt;!DynamicPoses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DrawingSystem&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!GraphicsChange&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalettesChange&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalettesEffects&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PlayerFeatures&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!YoshiFeatures&amp;lt;/code&amp;gt;, se incluyen desde &amp;lt;code&amp;gt;Options.asm&amp;lt;/code&amp;gt;. Sus valores indican qué funciones se instalaron; no se cambian durante el juego.&lt;br /&gt;
&lt;br /&gt;
=== Defines generados ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme crea estos defines al instalar los recursos y los añade a &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
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, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;my-sprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;my sprite&amp;lt;/code&amp;gt; se convierten en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. 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 &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Poses dinámicas y poses de dibujo ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia o ejemplo !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; || ID de unos gráficos de pose declarados en el DynamicInfo. Se utiliza para solicitar su carga con &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseMySprite000&amp;lt;/code&amp;gt; || Dirección ROM de esos gráficos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseMySprite000Size&amp;lt;/code&amp;gt; || Tamaño de esos gráficos en bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; || ID de una pose del DrawInfo. Se utiliza para dibujarla con &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;DrawStatic&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; || Distancia horizontal calculada desde el DrawInfo para saber cuándo el sprite deja de verse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; || Distancia vertical calculada desde el DrawInfo para la misma comprobación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; no se utiliza en lugar de un &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Paletas y efectos ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia o ejemplo !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteIDMyPalette&amp;lt;/code&amp;gt; || ID de una paleta declarada desde el DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; || Dirección ROM de sus colores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyPaletteSize&amp;lt;/code&amp;gt; || Tamaño de la paleta en bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; || Indica dónde comienza la lista de paletas de ese DynamicInfo. Se entrega a &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; y a sus variantes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; || ID de un efecto de &amp;lt;code&amp;gt;my_effect.paleffect&amp;lt;/code&amp;gt;. El número final identifica el efecto dentro del archivo; los IDs globales comienzan en 1.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyTargetRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PaletteMyTargetHSL&amp;lt;/code&amp;gt; || Dirección ROM de una paleta de destino convertida para una transición RGB o HSL. Se genera cuando un efecto necesita esa paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyTargetRGBSize&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PaletteMyTargetHSLSize&amp;lt;/code&amp;gt; || Tamaño en bytes de esas paletas convertidas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres de los ejemplos usan la misma normalización: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. Los defines se generan durante la instalación y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y buffers ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia o ejemplo !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt; || ID de un recurso general del DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt; || Dirección ROM de ese recurso.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt; || Tamaño del recurso en bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferIDMyBuffer&amp;lt;/code&amp;gt; || ID de un buffer insertado por la herramienta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferMyBuffer&amp;lt;/code&amp;gt; || Dirección del buffer insertado en la ROM; no es una variable temporal de RAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferMyBufferSize&amp;lt;/code&amp;gt; || Tamaño del buffer en bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres dependen de los recursos instalados. Se normalizan del mismo modo: &amp;lt;code&amp;gt;my_resource&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyResource&amp;lt;/code&amp;gt;. Consulta &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; para ver los nombres y valores de tu instalación.&lt;br /&gt;
&lt;br /&gt;
==== Cantidades y tablas generadas ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfDynamicPoses&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfPoses&amp;lt;/code&amp;gt; || Cantidad de poses dinámicas y de poses de dibujo instaladas, respectivamente.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfPalettes&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfResources&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfBuffers&amp;lt;/code&amp;gt; || Cantidad de paletas normales, recursos generales y buffers insertados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfPaletteEffects&amp;lt;/code&amp;gt; || 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 &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteTableSize&amp;lt;/code&amp;gt; || Cantidad total de entradas en las listas de paletas de los DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteIDTables&amp;lt;/code&amp;gt; || Dirección de la tabla de IDs de esas listas de paletas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAddrTables&amp;lt;/code&amp;gt; || Dirección de la tabla con las direcciones ROM de sus colores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsTypes&amp;lt;/code&amp;gt; || Tabla con el tipo de cada efecto instalado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsChannels1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsChannels2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsChannels3&amp;lt;/code&amp;gt; || Tablas con los valores de color de cada efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsRatios1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsRatios2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsRatios3&amp;lt;/code&amp;gt; || Tablas con los ratios que controlan cuánto se aplica cada cambio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferTable&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteTables&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsTable&amp;lt;/code&amp;gt; || Direcciones de las tablas que el parche publica para esos datos.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Defines de rutinas ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define o familia !! Uso&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AllowedGameMode&amp;lt;/code&amp;gt; || Comprueba si el modo de juego actual permite procesar las operaciones correspondientes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; || Elige las partes de VRAM disponibles para poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; || Solicita una pose por su ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; || Prepara las copias de gráficos de una pose a VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SetPropertyAndOffset&amp;lt;/code&amp;gt; || Obtiene la ubicación y propiedades de los gráficos de una pose dinámica para dibujarla.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Draw&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!Draw_Return&amp;lt;/code&amp;gt; || Entrada y punto de retorno utilizados por las rutinas de dibujo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RemapOamTile&amp;lt;/code&amp;gt; || Ajusta el número de tile para utilizar la ubicación real de los gráficos dinámicos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!IsValid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!XIsValid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!YIsValid&amp;lt;/code&amp;gt; || Comprobaciones utilizadas por el dibujo para decidir si un tile puede mostrarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AssignPalette&amp;lt;/code&amp;gt; || Selecciona el destino de una paleta según el modo de asignación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LoadPaletteOnBuffer&amp;lt;/code&amp;gt; || Carga datos de paleta en un espacio de trabajo para procesarlos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SetRGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!SetHSLBase&amp;lt;/code&amp;gt; || Prepara los colores para calcular efectos RGB o HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RGBToHSL&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!HSLToRGB&amp;lt;/code&amp;gt; || Convierte entre ambos sistemas de color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RGBMerge&amp;lt;/code&amp;gt; || Convierte colores RGB separados al formato de paleta de SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Mix...&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!MixAndMerge...&amp;lt;/code&amp;gt; || Aplica cambios a uno o varios componentes del color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalTransitionRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PalTransitionHSL&amp;lt;/code&amp;gt; || Calcula el cambio de una paleta a otra.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalTransitionAndMergeRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PalTransitionAndMergeHSL&amp;lt;/code&amp;gt; || Calcula la transición y deja el resultado en formato de SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DoEffect&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!DoEffectAndMerge&amp;lt;/code&amp;gt; || Aplica un efecto mediante su ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalFunctionRGB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalFunctionHSL&amp;lt;/code&amp;gt; y variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Nombres reservados para funciones de color que todavía no están implementadas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Routines&amp;lt;/code&amp;gt; es la dirección de la tabla desde la que se obtienen estas llamadas. No necesitas calcular sus posiciones para usar los defines publicados.&lt;br /&gt;
&lt;br /&gt;
== Estado del CPU y memoria temporal ==&lt;br /&gt;
&lt;br /&gt;
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: &#039;&#039;&#039;tamaño y contenido son cosas distintas&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Estas reglas se aplican a las llamadas de este artículo, salvo las excepciones indicadas en cada entrada:&lt;br /&gt;
&lt;br /&gt;
* Ejecuta el código en modo nativo, con el modo decimal desactivado. Las operaciones matemáticas del sistema utilizan números binarios.&lt;br /&gt;
* &#039;&#039;&#039;Direct page D:&#039;&#039;&#039; &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; en LoROM y &amp;lt;code&amp;gt;$3000&amp;lt;/code&amp;gt; en el contexto habitual de SA-1 Pack. Las direcciones cortas como &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; se interpretan respecto de esa base. Las llamadas no preparan ni cambian D por ti.&lt;br /&gt;
* &#039;&#039;&#039;Banco de datos DBR:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;$00-$3F&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;$80-$BF&amp;lt;/code&amp;gt;. 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. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; tiene un requisito específico de DBR, explicado en su entrada.&lt;br /&gt;
* 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.&lt;br /&gt;
* &#039;&#039;&#039;Flags:&#039;&#039;&#039; 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.&lt;br /&gt;
* &#039;&#039;&#039;Memoria temporal:&#039;&#039;&#039; 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.&lt;br /&gt;
* &#039;&#039;&#039;Pila:&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;PLP&amp;lt;/code&amp;gt; también reemplaza ese carry.&lt;br /&gt;
&lt;br /&gt;
== Rutinas para sprites ==&lt;br /&gt;
&lt;br /&gt;
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: &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt;. La ruta del include es relativa al archivo ASM del sprite.&lt;br /&gt;
&lt;br /&gt;
Los requisitos de DBR, D, flags y pila se explican en [[#Estado del CPU y memoria temporal|Estado del CPU y memoria temporal]]. La tabla siguiente distingue el tamaño de los registros de los valores que conservan.&lt;br /&gt;
&lt;br /&gt;
Para usar llamadas como &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, escribe su nombre directamente, como muestran los ejemplos. No añadas &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt; delante. Salvo que se indique lo contrario, X debe contener el número del slot que ocupa el sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y scratch de las llamadas para sprites&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Entra con X e Y en modo de 8 bits. El tamaño de A depende de la llamada:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Llamada !! A al entrar !! Registros al volver !! Scratch que puede sobrescribir&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;&lt;br /&gt;
| 8 bits.&lt;br /&gt;
| A cambia y queda en 8 bits. X e Y conservan su valor y tamaño.&lt;br /&gt;
| No utiliza scratch; modifica las tablas de Dynamic Xtreme descritas en su entrada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;&lt;br /&gt;
| 16 bits con &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; habilitado; 8 bits si está deshabilitado, sin utilizar el offset de tabla.&lt;br /&gt;
| A e Y pueden cambiar. X vuelve a cargarse desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; cuando se utiliza para el trabajo interno. La variante sin carga devuelve información en Y. Los tres quedan en 8 bits.&lt;br /&gt;
| &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$65-$67&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$D5&amp;lt;/code&amp;gt;, según el camino utilizado. Con efectos, también puede utilizar los temporales de efectos indicados más abajo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;&lt;br /&gt;
| 16 bits.&lt;br /&gt;
| A e Y pueden cambiar. X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. Los tres quedan en 8 bits.&lt;br /&gt;
| &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$47-$51&amp;lt;/code&amp;gt; cuando necesita preparar una carga nueva.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt;&lt;br /&gt;
| 16 bits.&lt;br /&gt;
| A e Y pueden cambiar. Si dibuja, X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; si no hay pose válida, conserva el X de entrada. Los tres quedan en 8 bits.&lt;br /&gt;
| &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$45-$4F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;. Con desplazamiento adicional, también &amp;lt;code&amp;gt;$8B-$8C&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;&lt;br /&gt;
| 8 bits.&lt;br /&gt;
| A e Y pueden cambiar. X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. Los tres quedan en 8 bits.&lt;br /&gt;
| &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; y los temporales utilizados por la carga de colores; también los de efectos cuando corresponde.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; y variante HSL&lt;br /&gt;
| 16 bits.&lt;br /&gt;
| A e Y pueden cambiar. Aunque X recibe una paleta al entrar, al volver contiene &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. Los tres quedan en 8 bits.&lt;br /&gt;
| Los temporales de efectos, &amp;lt;code&amp;gt;$05-$06&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$F0-$F3&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
PIXI mantiene &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; de los ejemplos pertenece a la rutina del sprite.&lt;br /&gt;
&lt;br /&gt;
=== RenderBox ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; 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).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen,x&amp;lt;/code&amp;gt;: distancias horizontal y vertical permitidas fuera de la pantalla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite está en pantalla o dentro de la distancia permitida fuera de sus bordes; se debe ejecutar la long routine.&lt;br /&gt;
* Carry desactivado: el sprite está demasiado lejos de la pantalla para dibujarse; se debe ejecutar la short routine.&lt;br /&gt;
&lt;br /&gt;
Cuando el sprite está demasiado lejos, establece &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Esto indica que deberá volver a obtener su paleta y su pose cuando se acerque a la pantalla. También guarda en &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt; el volteo que resulta de combinar &amp;lt;code&amp;gt;!GlobalFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip&amp;lt;/code&amp;gt;. En sprites normales actualiza además las variables que indican si está fuera de pantalla horizontal o verticalmente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
print &amp;quot;INIT &amp;quot;,pc&lt;br /&gt;
    LDA.b #!RenderBoxXDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderXDistanceOutOfScreen,x&lt;br /&gt;
    LDA.b #!RenderBoxYDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderYDistanceOutOfScreen,x&lt;br /&gt;
    ; Aquí va el resto de la inicialización del sprite&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
SpriteCode:&lt;br /&gt;
    !RenderBox&lt;br /&gt;
    BCS .LongRoutine&lt;br /&gt;
&lt;br /&gt;
.ShortRoutine&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    %SubOffScreen()&lt;br /&gt;
    ; Aquí va la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&lt;br /&gt;
.LongRoutine&lt;br /&gt;
    ; Aquí van el manejo de paletas, poses y dibujo&lt;br /&gt;
    ; y la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La llamada a &amp;lt;code&amp;gt;%SubOffScreen()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; se generan desde el DrawInfo y se guardan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. 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, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Si el sprite utiliza varios DrawInfo, utiliza la mayor distancia horizontal y la mayor distancia vertical entre ellos.&lt;br /&gt;
&lt;br /&gt;
=== PaletteAssignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; selecciona una paleta del DynamicInfo usando &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
Si el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; está activado (&amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;), también procesa los efectos globales de paleta correspondientes. Si está desactivado, la paleta queda excluida del efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cómo se elige la paleta&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; indica qué paleta de sprites se permite utilizar y si sus colores reciben el efecto global. Su formato es &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt;: 0 excluye la paleta del efecto global; 1 permite aplicarlo.&lt;br /&gt;
* &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt;: con asignación manual, selecciona una paleta entre 8 y F. &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; elige la 8, &amp;lt;code&amp;gt;001&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* Con asignación automática, &amp;lt;code&amp;gt;PPP = 000&amp;lt;/code&amp;gt; permite buscar entre las ocho paletas. Un valor &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; limita la búsqueda a las paletas 8-B; un valor &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; la limita a las C-F.&lt;br /&gt;
* Los cuatro bits bajos no se utilizan para estas opciones.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; decide quién elige el destino y si se cargan colores. Su formato es &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 00&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;): automático. Dynamic Xtreme elige una de las paletas permitidas y carga los colores del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 01&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;): manual. Utiliza la paleta indicada en &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; y carga los colores del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 10&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;): manual sin carga. Utiliza la paleta indicada en &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; con los colores que ya tiene el nivel.&lt;br /&gt;
&lt;br /&gt;
En sprites normales, &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; es &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; es &amp;lt;code&amp;gt;!ExtraProp2,x&amp;lt;/code&amp;gt;. Lo habitual es usar el primer Extra Byte con formato &amp;lt;code&amp;gt;EPPPVVVV&amp;lt;/code&amp;gt; y copiar sus cuatro bits bajos a &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, con asignación manual, &amp;lt;code&amp;gt;!PaletteOption,x = $A0&amp;lt;/code&amp;gt; utiliza la paleta A y permite el efecto global. Si &amp;lt;code&amp;gt;!Version,x = 1&amp;lt;/code&amp;gt;, carga en ella la segunda paleta de la lista del DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; correspondiente al DynamicInfo que contiene las paletas.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;: índice de la paleta dentro de la tabla.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: última versión procesada. Se compara con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; para detectar cambios y debe inicializarse en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;: selección de paleta y participación en el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt;: asignación automática, manual o manual sin carga.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite puede dibujarse con la paleta asignada.&lt;br /&gt;
* Carry desactivado: el sprite todavía no tiene una paleta lista para dibujar.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta asignada, con valores de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos para las paletas 8-F.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: se actualiza con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; cuando se procesa la nueva asignación.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignment&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre del recurso se normaliza en PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== PaletteAssignmentNoUpload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; elige la paleta igual que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
El bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;) 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 &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; elige la paleta del DynamicInfo: 0 para la primera, 1 para la segunda, etc. &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: 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, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; elige el destino automáticamente, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; usa el indicado en PPP y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt;: mismas opciones que en &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: última versión procesada, utilizada para detectar cambios respecto de &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;. Debe inicializarse en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite tiene una paleta asignada; desactivado si no pudo obtenerse.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta asignada.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: se actualiza con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; cuando se procesa la nueva asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: número que identifica la paleta elegida del DynamicInfo, cuando se utiliza un modo que carga sus colores.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base en ROM.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    ; Aquí se prepara y concatena el efecto.&lt;br /&gt;
    ; Conserva Y y la dirección de $02-$04 para esa llamada.&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; dice qué paleta del DynamicInfo se eligió; &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; dice cuál de las paletas 8-F utilizará el sprite para dibujarse. Los datos de &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;, eliminando los separadores.&lt;br /&gt;
&lt;br /&gt;
=== Upload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; consigue los gráficos de la pose que el sprite quiere mostrar. La pose se selecciona sumando &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico base.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt;: índice que se suma al ID base.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt;: volteos que se combinarán para dibujar.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* Carry desactivado: el sprite todavía no tiene una pose disponible.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt;: estado de la pose disponible para dibujar.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    !Upload&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== UploadWithoutPoseOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; solicita directamente el ID dinámico entregado en A, sin sumarle &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;. Como &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, reutiliza los gráficos si ya están en VRAM y puede seguir mostrando la pose anterior mientras no consiga cargar la nueva.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: existe &amp;lt;code&amp;gt;%DXExtendedUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;, pero actualmente &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; no publica el alias &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico exacto.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt;: volteos del sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite tiene una pose disponible para dibujar; desactivado si todavía no tiene ninguna.&lt;br /&gt;
* Guarda la pose que se puede dibujar en &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt; y la ubicación de sus gráficos en &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;, igual que &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite003&lt;br /&gt;
    !UploadWithoutPoseOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite003&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== DXDraw ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; dibuja una pose utilizando los gráficos dinámicos disponibles para el sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID de la pose de dibujo.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;): propiedades adicionales, con formato &amp;lt;code&amp;gt;YXCC----&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;): prioridad máxima de los tiles; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; máxima, &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; alta, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; propia del tipo de sprite y &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; mínima.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;: paleta, volteo y ubicación de los gráficos disponibles.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose en pantalla. Si &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no dibuja. A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDraw&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, las poses deben estar en el mismo orden en el DrawInfo y el DynamicInfo. Se utiliza &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; porque indica qué pose se puede dibujar: si la nueva todavía no se pudo cargar, seguirá mostrando la anterior.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres de recurso y pose se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Este ID de dibujo es distinto de los IDs &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; del DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
=== DXDrawWithOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Las mismas entradas de &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;): desplazamiento horizontal de 8 bits con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;): desplazamiento vertical de 8 bits con signo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja igual que &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;, pero suma los desplazamientos que preparaste. Un valor positivo en &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; mueve el dibujo a la derecha; en &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt;, hacia abajo. Los valores negativos lo mueven a la izquierda o hacia arriba.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$08&lt;br /&gt;
    STA !XOffsetParam&lt;br /&gt;
    LDA #$F8&lt;br /&gt;
    STA !YOffsetParam&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDrawWithOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo desplaza el dibujo 8 píxeles a la derecha y 8 hacia arriba. &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; el nombre se normaliza en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ReplacePalette ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Suele utilizarse después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;: primero se asigna la paleta sin cargar sus colores y después se reemplazan por los que quieres mostrar. Antes de llamar a &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, coloca en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; la dirección de los nuevos colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* A en modo de 8 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de la nueva paleta en BGR555.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta ya asignada.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;: participación en el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta; si los nuevos colores todavía no están listos, se conservan los anteriores.&lt;br /&gt;
* Carry desactivado: la paleta todavía no tiene colores listos para dibujar.&lt;br /&gt;
&lt;br /&gt;
Mantiene el mismo ID de paleta, pero solicita cambiar sus colores. Al marcar que el efecto debe volver a calcularse, utiliza &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; si nunca se habían obtenido colores para dibujar, o &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; si puede seguir mostrando los anteriores mientras prepara los nuevos.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ReplaceSpritePalette:&lt;br /&gt;
    ; Ejecutar cuando se necesite cambiar una paleta ya asignada.&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;8&lt;br /&gt;
    STA $03&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
    !ReplacePalette&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyAlternatePalette&amp;lt;/code&amp;gt; es la dirección de una paleta insertada desde los recursos declarados en un DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_alternate_palette&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyAlternatePalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ConcatenateRGBPaletteEffectToGlobal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, y después aplica el global sobre ese resultado. Llámala después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, que deja preparada la paleta original.&lt;br /&gt;
&lt;br /&gt;
El uso habitual es asignar primero la paleta con &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; y, si el carry está activado, llamar a esta rutina para aplicar los efectos y completar la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID del efecto local RGB.&lt;br /&gt;
* X de 8 bits: copia aquí el valor de &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;LDA !Palette,x&amp;lt;/code&amp;gt; seguido de &amp;lt;code&amp;gt;TAX&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
* Y de 8 bits: conserva el valor que dejó &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;. El valor 1 obliga a calcular de nuevo el efecto; 0 permite reutilizar el resultado anterior si no cambió nada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base BGR555 preparada por la asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;: el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; debe estar activado para combinar con el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta. Si el nuevo efecto todavía no está listo, se sigue mostrando el anterior.&lt;br /&gt;
* Carry desactivado: todavía no hay colores listos para dibujar esa paleta.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyRGBEffect0&lt;br /&gt;
    !ConcatenateRGBPaletteEffectToGlobal&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y &amp;lt;code&amp;gt;!PaletteEffectIDMyRGBEffect0&amp;lt;/code&amp;gt; desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. Ambos quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Si se necesita Y para seleccionar el efecto mediante una tabla, conserva su valor con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; y restáuralo con &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; antes de concatenar.&lt;br /&gt;
&lt;br /&gt;
=== ConcatenateHSLPaletteEffectToGlobal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt; permite que la paleta del sprite tenga un efecto HSL propio, como &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, y siga siendo afectada por el efecto global. Primero aplica el efecto local y después el global. Llámala después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, que deja preparada la paleta original.&lt;br /&gt;
&lt;br /&gt;
El uso habitual es asignar primero la paleta con &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; y, si el carry está activado, llamar a esta rutina para aplicar los efectos y completar la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID del efecto local HSL.&lt;br /&gt;
* X de 8 bits: copia aquí el valor de &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;LDA !Palette,x&amp;lt;/code&amp;gt; seguido de &amp;lt;code&amp;gt;TAX&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
* Y de 8 bits: conserva el valor que dejó &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;. El valor 1 obliga a calcular de nuevo el efecto; 0 permite reutilizar el resultado anterior si no cambió nada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base BGR555 preparada por la asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;: el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; debe estar activado para combinar con el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta. Si el nuevo efecto todavía no está listo, se sigue mostrando el anterior.&lt;br /&gt;
* Carry desactivado: todavía no hay colores listos para dibujar esa paleta.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyHSLEffect0&lt;br /&gt;
    !ConcatenateHSLPaletteEffectToGlobal&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y &amp;lt;code&amp;gt;!PaletteEffectIDMyHSLEffect0&amp;lt;/code&amp;gt; desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. Quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y utilizan nombres normalizados en PascalCase: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra. Conserva Y con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; si lo utilizas temporalmente para seleccionar el efecto.&lt;br /&gt;
&lt;br /&gt;
Ambas variantes de concatenación realizan las conversiones necesarias si el efecto local y el global utilizan espacios de color diferentes. Consulta [[es/Dynamic_Xtreme_files_and_formats#Tipos_de_efectos|Tipos de efectos]] para identificar los efectos RGB y HSL.&lt;br /&gt;
&lt;br /&gt;
== Rutinas y Macros Generales ==&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!NormalPoseIndex,x&amp;lt;/code&amp;gt;, escríbelo entre comillas para que Asar lo lea como un solo argumento. Utiliza &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; al entregar un valor inmediato, como &amp;lt;code&amp;gt;#$04&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Aplica también las reglas de [[#Estado del CPU y memoria temporal|DBR, direct page, flags y pila]]. Los contratos de cada familia indican qué registros y temporales debes guardar si necesitas conservarlos.&lt;br /&gt;
&lt;br /&gt;
=== Consulta rápida de llamadas y retornos ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Llamada o familia !! Retorno incluido !! Cómo utilizarla&lt;br /&gt;
|-&lt;br /&gt;
| Aliases para sprites: &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; y los demás aliases de esta categoría.&lt;br /&gt;
| La llamada vuelve y el código continúa después del alias.&lt;br /&gt;
| Escribe el alias directamente, sin anteponer &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;. Tu rutina conserva su propio retorno.&lt;br /&gt;
|-&lt;br /&gt;
| [[#GeneralUpload|GeneralUpload]], [[#Upload (macro general)|Upload (macro general)]] y [[#StandardSpriteUpload|StandardSpriteUpload]].&lt;br /&gt;
| &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Coloca la macro al final de una rutina llamada con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Draw|Draw]], [[#StandardSpriteDraw|StandardSpriteDraw]] y [[#DrawStatic|DrawStatic]].&lt;br /&gt;
| &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Coloca la macro al final de una rutina llamada con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#PaletteAssignment (macro general)|PaletteAssignment]], [[#PaletteAssignmentNoUpload (macro general)|PaletteAssignmentNoUpload]], [[#StandardSpritePaletteAssignment|StandardSpritePaletteAssignment]] y [[#StandardSpritePaletteAssignmentNoUpload|StandardSpritePaletteAssignmentNoUpload]].&lt;br /&gt;
| &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Coloca la macro al final de una rutina llamada con &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#ReplacePalette (macro general)|ReplacePalette]], [[#Combinar un efecto propio con el global|ConcatenateRGBPaletteEffectToGlobal y ConcatenateHSLPaletteEffectToGlobal]], en sus versiones de macro general.&lt;br /&gt;
| &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Coloca la macro al final de una rutina llamada con &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[#LoadPaletteIDAndAddress|LoadPaletteIDAndAddress]] y [[#DefineDynamicSpaceConfig|DefineDynamicSpaceConfig]].&lt;br /&gt;
| Ninguno: continúa el código siguiente.&lt;br /&gt;
| Puedes escribir más código después de la macro. Tu rutina debe incluir su propio retorno.&lt;br /&gt;
|-&lt;br /&gt;
| [[#Cargar colores con TransferPalette|TransferPaletteFromAddress, FromPointer, FromTable, Resource y ResourceWithLength]].&lt;br /&gt;
| Ninguno: continúa el código siguiente.&lt;br /&gt;
| Comprueba el carry después de la macro y continúa o termina tu rutina según el resultado.&lt;br /&gt;
|-&lt;br /&gt;
| Macros de [[#Efectos de paleta|preparación de bases, mezcla, transición, DoEffect y conversión]], incluidas sus variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Ninguno: continúa el código siguiente.&lt;br /&gt;
| Puedes encadenar operaciones después de la macro. Las dos macros de concatenación son la excepción indicada arriba.&lt;br /&gt;
|-&lt;br /&gt;
| Macros de [[#PPU|transferencia a VRAM y CGRAM]], incluidas las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;, y macros de [[#Matemáticas|matemáticas]].&lt;br /&gt;
| Ninguno: continúa el código siguiente.&lt;br /&gt;
| Tu rutina debe incluir su propio retorno.&lt;br /&gt;
|-&lt;br /&gt;
| Rutinas del parche [[#DynamicPoseSpaceConfig|DynamicPoseSpaceConfig]], [[#TakeDynamicRequest|TakeDynamicRequest]] y [[#DynamicRoutine|DynamicRoutine]].&lt;br /&gt;
| La rutina llamada retorna con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Utiliza &amp;lt;code&amp;gt;JSL !NombreDeLaRutina&amp;lt;/code&amp;gt;. Al volver, se ejecuta la instrucción que sigue al &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;; tu rutina conserva su propio retorno.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, una rutina que contiene &amp;lt;code&amp;gt;%Upload(...)&amp;lt;/code&amp;gt; se llama con &amp;lt;code&amp;gt;JSR PoseManagement&amp;lt;/code&amp;gt; y ya termina con el &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; de la macro. Una que contiene &amp;lt;code&amp;gt;%PaletteAssignment(...)&amp;lt;/code&amp;gt; se llama con &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt; y ya termina con su &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. En cambio, &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; realiza una llamada a la rutina compartida de PIXI y permite continuar después del alias: no es lo mismo que expandir &amp;lt;code&amp;gt;%Upload(...)&amp;lt;/code&amp;gt; directamente.&lt;br /&gt;
&lt;br /&gt;
=== Poses dinámicas ===&lt;br /&gt;
&lt;br /&gt;
==== DynamicPoseSpaceConfig ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt; y retorna con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; elige qué partes de la memoria gráfica (VRAM) puede usar Dynamic Xtreme para cargar poses dinámicas. Normalmente se llama desde el &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; de UberASM al entrar al nivel.&lt;br /&gt;
&lt;br /&gt;
Los defines con las configuraciones disponibles se encuentran en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, bajo los nombres &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 8 bits: una de las configuraciones &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus valores van de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicSpaceConfigSP4&amp;lt;/code&amp;gt; es una constante publicada en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permite utilizar SP4. Otras opciones incluyen &amp;lt;code&amp;gt;!DynamicSpaceConfigSP3&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt;. Selecciona una región que no se superponga con los gráficos estáticos utilizados por el nivel.&lt;br /&gt;
&lt;br /&gt;
==== DefineDynamicSpaceConfig ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DefineDynamicSpaceConfig()&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%DefineDynamicSpaceConfig(init, end, restricted)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;: ID del primer bloque de 16×16 del espacio.&lt;br /&gt;
* &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;: ID del último bloque de 16×16 del espacio. Ambos extremos se incluyen.&lt;br /&gt;
* &amp;lt;code&amp;gt;restricted&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; permite utilizar ese espacio para poses dinámicas; &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; lo restringe y el sistema no puede elegirlo para cargar poses.&lt;br /&gt;
&lt;br /&gt;
Los tres parámetros son constantes utilizadas al ensamblar y se escriben sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;. El primer bloque debe ser menor o igual que el último, y ambos deben estar entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt;. Por ejemplo, &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; hasta &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt; incluye 32 bloques.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cómo se numeran los bloques&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Para esta configuración, el espacio de gráficos de sprites se considera una cuadrícula de &#039;&#039;&#039;128×256 píxeles&#039;&#039;&#039;. La mitad superior, de 128×128, corresponde a SP1 y SP2; la mitad inferior, también de 128×128, corresponde a SP3 y SP4.&lt;br /&gt;
&lt;br /&gt;
La cuadrícula se divide en bloques de 16×16: hay &#039;&#039;&#039;8 bloques por fila y 16 filas&#039;&#039;&#039;, 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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Fila de tiles de 16×16 !! Col. 0 !! Col. 1 !! Col. 2 !! Col. 3 !! Col. 4 !! Col. 5 !! Col. 6 !! Col. 7&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$09&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$11&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$13&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$15&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$17&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
| &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$19&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$21&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$22&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$23&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$24&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$26&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$27&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
| &amp;lt;code&amp;gt;$28&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$29&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
| &amp;lt;code&amp;gt;$30&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$31&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$32&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$33&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$34&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$35&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$36&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$37&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
| &amp;lt;code&amp;gt;$38&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$39&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$41&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$42&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$43&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$44&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$45&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$46&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$47&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
| &amp;lt;code&amp;gt;$48&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$49&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 10&lt;br /&gt;
| &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$51&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$53&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$54&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$55&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$56&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$57&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 11&lt;br /&gt;
| &amp;lt;code&amp;gt;$58&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$59&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 12&lt;br /&gt;
| &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$61&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$62&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$63&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$64&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$65&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$66&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$67&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 13&lt;br /&gt;
| &amp;lt;code&amp;gt;$68&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$69&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 14&lt;br /&gt;
| &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$71&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$72&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$73&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$74&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$75&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$76&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$77&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 15&lt;br /&gt;
| &amp;lt;code&amp;gt;$78&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$79&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Sección !! Bloques !! Posición en la cuadrícula&lt;br /&gt;
|-&lt;br /&gt;
| SP1 || &amp;lt;code&amp;gt;$00–$1F&amp;lt;/code&amp;gt; || Primeras cuatro filas.&lt;br /&gt;
|-&lt;br /&gt;
| SP2 || &amp;lt;code&amp;gt;$20–$3F&amp;lt;/code&amp;gt; || Siguientes cuatro filas.&lt;br /&gt;
|-&lt;br /&gt;
| SP3 || &amp;lt;code&amp;gt;$40–$5F&amp;lt;/code&amp;gt; || Siguientes cuatro filas.&lt;br /&gt;
|-&lt;br /&gt;
| SP4 || &amp;lt;code&amp;gt;$60–$7F&amp;lt;/code&amp;gt; || Últimas cuatro filas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplos del parche&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Estas configuraciones utilizan los mismos rangos que las opciones predefinidas del parche. Colócalas en el &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; de UberASM, antes de que los sprites soliciten sus poses.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Utilizar solamente SP4:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    ; SP1, SP2 y SP3 restringidos.&lt;br /&gt;
    %DefineDynamicSpaceConfig($00, $5F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; SP4 disponible para poses dinámicas.&lt;br /&gt;
    %DefineDynamicSpaceConfig($60, $7F, $00)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Utilizar solamente SP3:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    ; SP1 y SP2 restringidos.&lt;br /&gt;
    %DefineDynamicSpaceConfig($00, $3F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; SP3 disponible para poses dinámicas.&lt;br /&gt;
    %DefineDynamicSpaceConfig($40, $5F, $00)&lt;br /&gt;
&lt;br /&gt;
    ; SP4 restringido.&lt;br /&gt;
    %DefineDynamicSpaceConfig($60, $7F, $80)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Utilizar SP3 y SP4:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    ; SP1 y SP2 restringidos.&lt;br /&gt;
    %DefineDynamicSpaceConfig($00, $3F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; SP3 y SP4 disponibles como un solo espacio.&lt;br /&gt;
    %DefineDynamicSpaceConfig($40, $7F, $00)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cada ejemplo es una alternativa: utiliza una configuración completa, cubriendo los bloques &amp;lt;code&amp;gt;$00–$7F&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* Escribe la configuración en &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt;, en los extremos del espacio indicado. No utiliza scratch.&lt;br /&gt;
* No carga gráficos ni mueve poses que ya estén en VRAM. Utilízala para preparar el espacio al entrar al nivel.&lt;br /&gt;
* No devuelve éxito o fallo en carry y no incluye &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;: el código continúa después de cada llamada. El &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; de los ejemplos termina el &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; de UberASM.&lt;br /&gt;
&lt;br /&gt;
==== TakeDynamicRequest ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$47-$51&amp;lt;/code&amp;gt; al preparar una carga nueva. Conserva DBR y D, tanto en éxito como en fallo. Se llama con &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt; y retorna con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !TakeDynamicRequest&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Y de 16 bits: ID exacto de la pose dinámica.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RequestPose:&lt;br /&gt;
    REP #$10&lt;br /&gt;
    LDY #!DynamicPoseIDMySprite000&lt;br /&gt;
    JSL !TakeDynamicRequest&lt;br /&gt;
    BCC .Unavailable&lt;br /&gt;
&lt;br /&gt;
    ; X contiene el índice hash de la pose solicitada.&lt;br /&gt;
    ; Aquí tu código puede guardar ese índice para dibujar la pose.&lt;br /&gt;
RTS&lt;br /&gt;
.Unavailable&lt;br /&gt;
    ; Aquí se maneja la falta de recursos.&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores y escribiendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== DynamicRoutine ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;$00-$0B&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$47-$51&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt; corresponde a los dos bytes de &amp;lt;code&amp;gt;$02-$03&amp;lt;/code&amp;gt; de la direct page. Conserva D y no cambia DBR: debes preparar el banco de las tablas antes de llamarla. Se llama con &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt; y retorna con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !DynamicRoutine&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; prepara esos datos antes de llamarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Datos que necesita la llamada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt;: variable interna de 16 bits que contiene el ID de la pose que se va a copiar.&lt;br /&gt;
* 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.&lt;br /&gt;
&lt;br /&gt;
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. &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; realiza ambas tareas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo de funcionamiento&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Cuando un sprite solicita una pose que todavía no está en VRAM, &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; busca dónde colocarla. Después guarda su ID en &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt; y llama a &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; con la posición elegida en A. Esta última prepara la copia de los gráficos; el NMI ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
Para cargar una pose desde el código de un sprite, utiliza &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. Si necesitas hacer la solicitud directamente mediante su ID, utiliza &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt;. Llamar a &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; requiere preparar también la variable interna del ID, el banco de datos y el espacio de destino descritos arriba.&lt;br /&gt;
&lt;br /&gt;
==== GeneralUpload ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;, X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; con &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, no se conserva X. Puede sobrescribir &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$47-$51&amp;lt;/code&amp;gt;, incluidos los temporales de una solicitud nueva. Conserva DBR y D. Incluye &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;: llama con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt; a la rutina que contiene la macro.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%GeneralUpload(Pose16, checkLast, sprite, flip, safeCheck, withoutOffset,&lt;br /&gt;
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,&lt;br /&gt;
    globalFlip, localFlip, lastFlip)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La firma anterior muestra el orden de los parámetros; escribe la llamada en una sola línea.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Pose16&amp;lt;/code&amp;gt;: 0 utiliza índices de pose de 8 bits; 1 utiliza índices de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt;: 1 permite seguir dibujando la pose anterior si no se pudo obtener la nueva; 0 desactiva esa opción.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 0 para usar variables propias sin recuperar el índice del sprite; 1 para trabajar con las tablas del sprite, recuperando X desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 2 funciona como 1, pero solicita la pose sin comparar ni cambiar &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;flip&amp;lt;/code&amp;gt;: 1 combina &amp;lt;code&amp;gt;globalFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;localFlip&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;; 0 omite esa actualización.&lt;br /&gt;
* &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt;: 1 evita repetir la solicitud en el mismo frame utilizando &amp;lt;code&amp;gt;safeLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;safeHigh&amp;lt;/code&amp;gt;; 0 omite la comprobación.&lt;br /&gt;
* &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;: 0 suma &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt; al ID base; 1 utiliza directamente el ID recibido.&lt;br /&gt;
* &amp;lt;code&amp;gt;safeLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;safeHigh&amp;lt;/code&amp;gt;: variables que guardan los bytes bajo y alto del frame de la solicitud. Se escriben incluso cuando &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; es 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt;: variable del índice de pose deseado.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;: variable del último índice de pose disponible.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;: variable que identifica la entrada donde Dynamic Xtreme guarda la ubicación de los gráficos en VRAM. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; indica que todavía no hay gráficos disponibles.&lt;br /&gt;
* &amp;lt;code&amp;gt;globalFlip&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;localFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variables del volteo global, local y efectivo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada adicional&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico base o exacto, según &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Para &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; debe contener el índice del sprite.&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt;, la macro solicita la pose aunque &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sean iguales, y deja &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sin modificar. Si consigue los gráficos, guarda su ubicación en &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;. Si la solicitud falla y &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; es 1, puede seguir usando los gráficos anteriores. &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; sigue controlando si se permite repetir la solicitud durante el mismo frame.&lt;br /&gt;
&lt;br /&gt;
Este valor 2 no cambia el tamaño de los índices. Para utilizar variables de índice de 16 bits se selecciona &amp;lt;code&amp;gt;Pose16 = 1&amp;lt;/code&amp;gt;. El ID dinámico entregado en A siempre es de 16 bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Devuelve el carry activado cuando hay una pose disponible para dibujar: la solicitada o la anterior si &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; al final; colócala al final de una rutina llamada con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %GeneralUpload(0, 1, 1, 1, 1, 0, &amp;quot;!NormalSafeFrameLowByte,x&amp;quot;, &amp;quot;!NormalSafeFrameHighByte,x&amp;quot;, &amp;quot;!NormalPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalGlobalFlip,x&amp;quot;, &amp;quot;!NormalLocalFlip,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las tablas de un sprite normal y un índice de pose de 8 bits. &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; el nombre se normaliza en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Upload (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; utiliza el mismo contrato de [[#GeneralUpload|GeneralUpload]], con &amp;lt;code&amp;gt;Pose16 = 0&amp;lt;/code&amp;gt;. A entra en 16 bits, X/Y en 8 bits, y los tres quedan en 8 bits. El valor de &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt; determina si X vuelve a cargarse desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. La macro incluye &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%Upload()&amp;lt;/code&amp;gt; es la variante de &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; para índices de pose de 8 bits. No debe confundirse con el alias para sprites &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Upload(sprite, checkLast, flip, safeCheck, withoutOffset,&lt;br /&gt;
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,&lt;br /&gt;
    globalFlip, localFlip, lastFlip)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Recibe los mismos datos que &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt;, pero los índices guardados en las variables siempre son de 8 bits. La macro ya incluye el &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
El parámetro &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt; también admite 2: omite la comparación con &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; y no actualiza esa variable, pero sí actualiza &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt; al obtener la pose. No habilita índices de 16 bits; para eso se utiliza &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;Pose16 = 1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sin modificar, el código del sprite puede controlar ese cambio.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %Upload(1, 1, 1, 1, 0, &amp;quot;!NormalSafeFrameLowByte,x&amp;quot;, &amp;quot;!NormalSafeFrameHighByte,x&amp;quot;, &amp;quot;!NormalPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalGlobalFlip,x&amp;quot;, &amp;quot;!NormalLocalFlip,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; es generado desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpriteUpload ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; utiliza el contrato de [[#GeneralUpload|GeneralUpload]] con &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;. A entra en 16 bits y X/Y en 8 bits. Al volver, X contiene &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; A e Y pueden cambiar y los tres quedan en 8 bits. Comparte sus scratch y termina con &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpriteUpload(withoutOffset, type)&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;: 0 suma &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; al ID base; 1 utiliza el ID exacto.&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A de 16 bits: ID dinámico.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* Tablas de poses y volteo de Dynamic Xtreme del tipo seleccionado, inicializadas como en las rutinas &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %StandardSpriteUpload(0, &amp;quot;Normal&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;, eliminando los separadores.&lt;br /&gt;
&lt;br /&gt;
=== Dibujo de poses ===&lt;br /&gt;
&lt;br /&gt;
Las macros de esta categoría terminan la rutina que las contiene mediante &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;. Los ejemplos deben llamarse con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;. A debe contener el ID de dibujo con 16 bits; &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;) se preparan igual que para &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Draw ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; entra con A de 16 bits y X/Y de 8 bits. A e Y pueden cambiar. Con &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; al preparar un dibujo válido; con &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, no se conserva el X inicial. Si no hay pose válida, X no cambia. Los tres registros quedan en 8 bits. Puede sobrescribir &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$45-$4F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;; con &amp;lt;code&amp;gt;offset = 1&amp;lt;/code&amp;gt;, también &amp;lt;code&amp;gt;$8B-$8C&amp;lt;/code&amp;gt;. Conserva DBR y D. Incluye &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%Draw()&amp;lt;/code&amp;gt; dibuja una pose dinámica. En la llamada indicas qué gráficos usar, su paleta, su volteo y la posición donde quieres dibujarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Draw(offset, sprite, lastPoseHashIndex, lastFlip, palette, xl, xh, yl, yh)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 utiliza las coordenadas entregadas; 1 añade &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;), de 8 bits con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 recupera el índice del sprite en X desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; antes de leer su paleta y posición; 0 omite ese paso.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;: variable que identifica dónde están registrados los gráficos de la pose en Dynamic Xtreme. Si contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no se dibuja.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variable o valor que indica el volteo con el que se dibujará.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de la paleta; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; selecciona la 8, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* &amp;lt;code&amp;gt;xl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;xh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición X.&lt;br /&gt;
* &amp;lt;code&amp;gt;yl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;yh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose con los gráficos indicados por &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMySprite_Frame0&lt;br /&gt;
    %Draw(0, 1, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. El ID debe corresponder a los gráficos dinámicos disponibles.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpriteDraw ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; comparte el contrato y las scratch de [[#Draw|Draw]], con &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;. 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 &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. Al terminar deja los tres registros en 8 bits e incluye &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpriteDraw(offset, type)&amp;lt;/code&amp;gt; dibuja una pose dinámica utilizando las tablas de Dynamic Xtreme del tipo de sprite seleccionado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 sin desplazamiento adicional; 1 utiliza los offsets de &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A de 16 bits: ID de dibujo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt;: propiedades y prioridad.&lt;br /&gt;
* Las tablas de paleta, último volteo e índice hash de Dynamic Xtreme del tipo seleccionado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;%Draw()&amp;lt;/code&amp;gt;, utilizando las tablas estándar. Es la macro que utilizan las rutinas PIXI &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para sprites normales, las rutinas PIXI preparan los aliases de coordenadas &amp;lt;code&amp;gt;!NormalXLow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!NormalXHigh&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!NormalYLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!NormalYHigh&amp;lt;/code&amp;gt;. Si se expande la macro directamente, también deben estar definidos, como en este ejemplo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!NormalXLow = !SpriteXLow&lt;br /&gt;
!NormalXHigh = !SpriteXHigh&lt;br /&gt;
!NormalYLow = !SpriteYLow&lt;br /&gt;
!NormalYHigh = !SpriteYHigh&lt;br /&gt;
&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMySprite_Frame0&lt;br /&gt;
    %StandardSpriteDraw(0, &amp;quot;Normal&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== DrawStatic ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$45-$4F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;; con &amp;lt;code&amp;gt;offset = 1&amp;lt;/code&amp;gt;, también &amp;lt;code&amp;gt;$8B-$8C&amp;lt;/code&amp;gt;. El parámetro &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt; no recupera X desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; en esta macro. Conserva DBR y D. Incluye &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt; dibuja una pose estática, declarada con &amp;lt;code&amp;gt;.IsStatic&amp;lt;/code&amp;gt; en el DrawInfo. Sus gráficos deben estar previamente cargados en las posiciones de VRAM indicadas por sus tiles.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%DrawStatic(offset, sprite, lastFlip, palette, xl, xh, yl, yh)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 sin desplazamiento adicional; 1 utiliza &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;), con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: parámetro conservado en la firma; la implementación actual de esta macro no lo utiliza.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variable o valor que indica el volteo; &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; dibuja sin volteo.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de paleta: &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; selecciona la 8, &amp;lt;code&amp;gt;#$02&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;#$0E&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* &amp;lt;code&amp;gt;xl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;xh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición X.&lt;br /&gt;
* &amp;lt;code&amp;gt;yl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;yh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas adicionales&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID de dibujo estático.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;): propiedades y prioridad.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;): 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose sin consultar la caché de gráficos dinámicos. No requiere &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; ni una llamada previa a &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$80&lt;br /&gt;
    STA !Tile&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMyStaticSprite_Frame0&lt;br /&gt;
    %DrawStatic(0, 1, #$00, #$04, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza el tile &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; si la pose está configurada para tomarlo desde &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, sin volteo y con la paleta A. &amp;lt;code&amp;gt;!PoseIDMyStaticSprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_static_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyStaticSprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Paletas ===&lt;br /&gt;
&lt;br /&gt;
Estas macros permiten elegir qué paleta usa un sprite, cargar sus colores y cambiarlos durante el juego.&lt;br /&gt;
&lt;br /&gt;
==== LoadPaletteIDAndAddress ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; y lee &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt;. Conserva DBR y D; carry no es un indicador de éxito. La expansión continúa en la instrucción siguiente.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%LoadPaletteIDAndAddress()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 8 bits: índice de la paleta dentro del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt;: guarda aquí el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; de tu DynamicInfo, con 16 bits, como muestra el ejemplo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: ID de la paleta.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de sus colores en ROM, en formato BGR555.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    STA $0E&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    LDA #$01            ; Segunda paleta del DynamicInfo&lt;br /&gt;
    %LoadPaletteIDAndAddress()&lt;br /&gt;
    ; $00-$01 contiene su ID y $02-$04 su dirección ROM.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En PIXI también puede llamarse mediante &amp;lt;code&amp;gt;%DXLoadPaletteIDAndAddress()&amp;lt;/code&amp;gt;, con las mismas entradas y resultados. Esta variante llama a una rutina compartida y después continúa con el código siguiente.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones bajos y guiones, y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignment (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; entra con X/Y de 8 bits y A de 16 bits cuando &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; cuando se utiliza internamente; con &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, no se conserva X. Al volver, los tres quedan en 8 bits. Puede sobrescribir &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$D5&amp;lt;/code&amp;gt; y los temporales de efectos cuando corresponda. Conserva DBR y D. La macro termina con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt; asigna y carga una paleta igual que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
Si la paleta ya estaba asignada, mantiene su temporizador de uso en 2 para que no sea reemplazada mientras se utiliza. Si el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; de las opciones está activado, también aplica el efecto global correspondiente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteAssignment(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 utiliza &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; para acceder a las tablas del sprite; 0 permite usar variables independientes del índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable que recibe la paleta asignada. Debe comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Los valores &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, ..., &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; corresponden a las paletas 8-F.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteAssignment&amp;lt;/code&amp;gt;: variable o valor con formato &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; permite que Dynamic Xtreme elija el destino y cargue los colores; &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; utiliza el destino que tú indicas y carga los colores; &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; utiliza ese destino con los colores que ya tiene el nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor con formato &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;. E = 1 permite aplicar el efecto global; E = 0 lo excluye. En modo manual, PPP elige entre la paleta 8 (&amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt;) y la F (&amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt;). En automático, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F. Los cuatro bits bajos no se usan para estas opciones.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteVersion&amp;lt;/code&amp;gt;: 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 &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt;: variable que guarda la última versión procesada. Debe comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualIDGroup&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt;: juntos forman el número con el que el sistema reconoce la paleta en los modos manuales. El primero indica el grupo: &amp;lt;code&amp;gt;#$FE&amp;lt;/code&amp;gt; para normal, &amp;lt;code&amp;gt;#$FC&amp;lt;/code&amp;gt; para cluster y &amp;lt;code&amp;gt;#$FD&amp;lt;/code&amp;gt; para extended. El segundo indica el tipo de sprite; en uno normal se utiliza &amp;lt;code&amp;gt;!CustomSpriteNumber,x&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
&lt;br /&gt;
También puedes crear grupos propios: por ejemplo, usar &amp;lt;code&amp;gt;manualIDGroup = #$FB&amp;lt;/code&amp;gt; para el jugador y &amp;lt;code&amp;gt;#$FA&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt; para distinguir los recursos dentro de cada uno. Los grupos &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$FD&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FC&amp;lt;/code&amp;gt; ya son utilizados por las rutinas de sprites normales, extended y cluster, respectivamente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada adicional&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* Si &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; debe contener el índice del sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: hay una paleta con la que se puede dibujar; desactivado si todavía no hay ninguna.&lt;br /&gt;
* Guarda el número de paleta en &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt; y actualiza &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt; cuando procesa la versión.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %PaletteAssignment(1, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!NormalPaletteAssignment,x&amp;quot;, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalVersion,x&amp;quot;, &amp;quot;!NormalLastVersion,x&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las variables de un sprite normal. &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; que termina la rutina, por lo que no debes añadir código después de ella.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignmentNoUpload (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; comparte el contrato de [[#PaletteAssignment (macro general)|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 &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; solo son válidas si se leyó una paleta del DynamicInfo. Termina con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; elige una paleta como &amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt;, pero deja pendiente la carga de sus colores. Permite aplicar después un efecto local y combinarlo con el global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteAssignmentNoUpload(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los parámetros son los mismos que en &amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt;. A recibe el offset de la tabla con 16 bits. &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt; deben comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;paletteVersion&amp;lt;/code&amp;gt; elige los colores de la lista del DynamicInfo: 0 para la primera paleta, 1 para la segunda, etc. &amp;lt;code&amp;gt;paletteAssignment&amp;lt;/code&amp;gt; decide el modo: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; automático, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; manual y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; manual sin cargar colores. &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: E permite el efecto global y PPP selecciona la paleta 8-F en manual. En automático, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F. Para aplicar después un efecto local sobre los colores del DynamicInfo, utiliza el modo automático o manual con carga.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: hay una paleta asignada; desactivado si no pudo obtenerse.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: número de la paleta asignada, de dos en dos entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt;: última versión procesada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: ID de la paleta seleccionada del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de sus colores.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
Usa los datos de &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
AssignPaletteForEffect:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %PaletteAssignmentNoUpload(1, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!NormalPaletteAssignment,x&amp;quot;, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalVersion,x&amp;quot;, &amp;quot;!NormalLastVersion,x&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Después de llamar a &amp;lt;code&amp;gt;AssignPaletteForEffect&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;, comprueba el carry y aplica el efecto usando los datos devueltos. Conserva Y y &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; para la llamada de concatenación.&lt;br /&gt;
&lt;br /&gt;
La macro ya termina la rutina con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. El código que aplica el efecto va después de la llamada &amp;lt;code&amp;gt;JSL AssignPaletteForEffect&amp;lt;/code&amp;gt;, no después de la macro dentro de esa rutina.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpritePaletteAssignment ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; comparte el contrato de [[#PaletteAssignment (macro general)|PaletteAssignment (macro general)]], con &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;. Entra con X preparado para leer las tablas del sprite y con &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; correspondiente al mismo sprite. Recupera X desde ese índice cuando lo utiliza internamente; A e Y pueden cambiar. Incluye &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpritePaletteAssignment()&amp;lt;/code&amp;gt; utiliza las variables de paleta del tipo de sprite indicado. Es la macro utilizada por las rutinas PIXI de asignación.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%StandardSpritePaletteAssignment(type, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualIDGroup&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;#$FE&amp;lt;/code&amp;gt; para normal, &amp;lt;code&amp;gt;#$FC&amp;lt;/code&amp;gt; para cluster o &amp;lt;code&amp;gt;#$FD&amp;lt;/code&amp;gt; para extended.&lt;br /&gt;
* También puedes elegir un grupo propio, por ejemplo &amp;lt;code&amp;gt;#$FB&amp;lt;/code&amp;gt; para el jugador o &amp;lt;code&amp;gt;#$FA&amp;lt;/code&amp;gt; para otro tipo de entidad, siempre que esos valores no estén siendo utilizados por otro grupo de tu proyecto.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt;: variable o valor que identifica el tipo de sprite en los modos manuales.&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* Las variables de Dynamic Xtreme para paleta, opciones, versión y última versión del tipo seleccionado, preparadas como en &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;: guarda la paleta asignada en la tabla del sprite y devuelve el carry activado cuando se puede dibujar con ella.&lt;br /&gt;
&lt;br /&gt;
La macro ya incluye un &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt; y no añadas código después de la macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %StandardSpritePaletteAssignment(&amp;quot;Normal&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt; al eliminar los separadores.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpritePaletteAssignmentNoUpload ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; comparte el contrato de [[#PaletteAssignmentNoUpload (macro general)|PaletteAssignmentNoUpload (macro general)]], con &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;. X y &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; deben identificar al mismo sprite al entrar. Conserva Y y &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; de su resultado si vas a concatenar un efecto. Incluye &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpritePaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; utiliza las variables del tipo de sprite seleccionado para asignar la paleta, dejando pendiente la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%StandardSpritePaletteAssignmentNoUpload(type, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Recibe los mismos parámetros y datos que &amp;lt;code&amp;gt;%StandardSpritePaletteAssignment()&amp;lt;/code&amp;gt;. A debe contener el offset de la tabla de paletas con 16 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;: guarda la paleta asignada y devuelve el carry, Y, el ID en &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; y la dirección en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;, con las condiciones indicadas en esa entrada.&lt;br /&gt;
&lt;br /&gt;
La macro ya incluye un &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL AssignPaletteForEffect&amp;lt;/code&amp;gt;. El código que aplica el efecto va después de esa llamada.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
AssignPaletteForEffect:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %StandardSpritePaletteAssignmentNoUpload(&amp;quot;Normal&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== ReplacePalette (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; entra con A, X e Y de 8 bits y con el puntero de origen preparado en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;. A e Y pueden cambiar; con &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; con &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, no se conserva X. Los tres quedan en 8 bits. Puede sobrescribir &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; y los temporales de efectos cuando corresponda. Conserva DBR y D. Termina con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ReplacePalette()&amp;lt;/code&amp;gt; sustituye los colores de una paleta que ya estás usando. Hace lo mismo que &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, pero tú eliges qué variables leer. Si otros sprites o códigos usan esa misma paleta, también verán los nuevos colores.&lt;br /&gt;
&lt;br /&gt;
Suele utilizarse después de una asignación sin carga, como &amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;. Primero obtienes la paleta asignada y después preparas en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; la dirección de los colores que quieres usar para reemplazarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%ReplacePalette(sprite, paletteOption, palette)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 obtiene el índice del sprite desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 0 utiliza variables independientes de ese índice.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor de las opciones de paleta. El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica si se aplica el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de la paleta de destino, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de los nuevos colores en BGR555.&lt;br /&gt;
* A en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Llámala cuando cambien los colores que quieres mostrar. Repetir la llamada cada frame obliga a preparar de nuevo la paleta y sus efectos.&lt;br /&gt;
&lt;br /&gt;
Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL ReplaceSpritePalette&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
ReplaceSpritePalette:&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;8&lt;br /&gt;
    STA $03&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
    %ReplacePalette(1, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyAlternatePalette&amp;lt;/code&amp;gt; es la dirección de una paleta insertada a partir de los recursos del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_alternate_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyAlternatePalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Cargar colores con TransferPalette ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros comunes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;: primer color que se cambiará, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Es un operando de 8 bits: &amp;lt;code&amp;gt;#$91&amp;lt;/code&amp;gt; empieza en el color 1 de la paleta 9; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; utiliza el número guardado en esa scratch.&lt;br /&gt;
* &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt;: cantidad de bytes que se copiarán. Es un valor conocido al ensamblar, &#039;&#039;&#039;sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;&#039;&#039;&#039;: &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; copia 15 colores. Debe ser mayor que cero y par, y la carga no debe pasar del último color de CGRAM.&lt;br /&gt;
* &amp;lt;code&amp;gt;GlobalEffect&amp;lt;/code&amp;gt;: utiliza &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; para cargar sin efecto global o &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; para que la paleta reciba el efecto global. Es una opción fija de la llamada, no una variable de RAM.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué hace GlobalEffect&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Comportamiento&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;GlobalEffect = 1&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas y resultado comunes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Entra con A, X e Y en modo de 8 bits. D debe ser &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; en LoROM o &amp;lt;code&amp;gt;$3000&amp;lt;/code&amp;gt; en el contexto habitual de SA-1 Pack. DBR debe permitir acceder al buffer de paletas de SMW: &amp;lt;code&amp;gt;$0703&amp;lt;/code&amp;gt; en LoROM o su espejo &amp;lt;code&amp;gt;$6703&amp;lt;/code&amp;gt; en SA-1. Los bancos habituales con espejos de RAM, como &amp;lt;code&amp;gt;$00-$3F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$80-$BF&amp;lt;/code&amp;gt;, permiten esos accesos. Si pasas tablas con direcciones de 16 bits, DBR también debe permitir leerlas.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* Las llamadas pueden modificar &amp;lt;code&amp;gt;$68-$6D&amp;lt;/code&amp;gt; cuando están habilitados los efectos; las variantes &amp;lt;code&amp;gt;FromAddress&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FromTable&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt;, incluida &amp;lt;code&amp;gt;ResourceWithLength&amp;lt;/code&amp;gt;, también utilizan &amp;lt;code&amp;gt;$65-$67&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
* No incluyen &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;: el código continúa después de la macro.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteFromAddress ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteFromAddress()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteFromAddress(Address, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Address&amp;lt;/code&amp;gt;: dirección de origen completa, sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Paleta 9, colores 1-F, con efecto global.&lt;br /&gt;
    %TransferPaletteFromAddress(!PaletteMyPalette, #$91, $001E, 1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; se genera al instalar una paleta declarada en &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; de un DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase: se eliminan espacios, guiones bajos y guiones, y se pone en mayúscula la inicial de cada palabra. Por ejemplo, &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteFromPointer ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteFromPointer()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteFromPointer(Pointer, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Pointer&amp;lt;/code&amp;gt;: dirección del primer byte de la scratch, sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;. Los tres bytes deben contener la dirección de origen en orden bajo, alto y banco. Por ejemplo, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Preparar la dirección de la paleta en $02-$04.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!PaletteMyPalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.b #!PaletteMyPalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
&lt;br /&gt;
    ; Paleta 9, colores 1-F, sin efecto global.&lt;br /&gt;
    %TransferPaletteFromPointer($02, #$91, $001E, 0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; se genera desde una paleta del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteFromTable ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteFromTable()&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;$65-$67&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteFromTable(TableAddr, TableBNK, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;TableAddr&amp;lt;/code&amp;gt;: operando que se lee con A de 16 bits para obtener los dos bytes de dirección.&lt;br /&gt;
* &amp;lt;code&amp;gt;TableBNK&amp;lt;/code&amp;gt;: operando que se lee con A de 8 bits para obtener el banco.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; $02-$03 contiene la dirección y $04 contiene el banco.&lt;br /&gt;
    %TransferPaletteFromTable(&amp;quot;$02&amp;quot;, &amp;quot;$04&amp;quot;, #$91, $001E, 1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A diferencia de &amp;lt;code&amp;gt;FromPointer&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteResource ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteResource()&amp;lt;/code&amp;gt; carga una paleta registrada en el DynamicInfo utilizando su tamaño completo. No necesitas escribir su dirección ni su cantidad de bytes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferPaletteResource(Name, CGRAMOffset, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Name&amp;lt;/code&amp;gt;: nombre normalizado de la paleta, sin prefijo &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt; y sin extensión. La macro utiliza &amp;lt;code&amp;gt;!Palette&amp;amp;lt;Name&amp;amp;gt;&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Palette&amp;amp;lt;Name&amp;amp;gt;Size&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; MyPalette contiene 15 colores.&lt;br /&gt;
    %TransferPaletteResource(MyPalette, #$91, 1)&lt;br /&gt;
    BCS .Accepted&lt;br /&gt;
    ; No se aceptó la carga directa: volver a intentarlo después.&lt;br /&gt;
    RTL&lt;br /&gt;
.Accepted&lt;br /&gt;
    ; Continuar con el resto del código.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo continúa en &amp;lt;code&amp;gt;.Accepted&amp;lt;/code&amp;gt; si se aceptó la carga directa o se prepararon los colores para el efecto global. El &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; pertenece al ejemplo, no a la macro.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; corresponde a los defines &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteMyPaletteSize&amp;lt;/code&amp;gt;, generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; desde la sección &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; del DynamicInfo. El nombre usa PascalCase eliminando espacios, guiones bajos y guiones: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;. Esta llamada no utiliza los defines &amp;lt;code&amp;gt;!Resource...&amp;lt;/code&amp;gt; de la sección &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; ni las paletas convertidas RGB/HSL de un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteResourceWithLength ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteResourceWithLength()&amp;lt;/code&amp;gt; utiliza la dirección de una paleta registrada, pero permite copiar solo la cantidad de bytes que indiques.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteResourceWithLength(Name, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Name&amp;lt;/code&amp;gt;: nombre normalizado de la paleta, igual que en &amp;lt;code&amp;gt;%TransferPaletteResource()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt;: cantidad de bytes que se copiarán, sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;. No debe superar el tamaño del recurso.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Copiar 4 colores al comienzo de la paleta 9, sin efecto global.&lt;br /&gt;
    %TransferPaletteResourceWithLength(MyPalette, #$90, $0008, 0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; utiliza el define &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt;, generado desde una paleta del DynamicInfo y publicado en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TransferPaletteCommon&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TransferPaletteData&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Efectos de paleta ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para ver ejemplos completos, consulta [[es/Dynamic_Xtreme_UberASM_guide#Aplicar un efecto global de paleta|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 [[es/Dynamic_Xtreme_UberASM_guide#Cambiar paletas durante el juego|Cambiar paletas durante el juego]] muestra cómo cargar los colores con &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; y comprobar si la llamada fue aceptada.&lt;br /&gt;
&lt;br /&gt;
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 [[es/Dynamic_Xtreme_files_and_formats#Tipos_de_efectos|Tipos de efectos]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;¿Qué llamada necesitas?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Quieres… !! Utiliza…&lt;br /&gt;
|-&lt;br /&gt;
| Teñir una paleta o cambiar su tono, saturación o luminosidad. || &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MixAndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Pasar de una paleta a otra. || &amp;lt;code&amp;gt;PaletteTransition&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Aplicar un efecto que ya definiste en un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. || &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DoEffectAndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Darle un efecto propio a un sprite y conservar además el efecto global. || &amp;lt;code&amp;gt;ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; o su variante HSL, después de asignar la paleta sin carga.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para calcular un efecto directamente, el proceso habitual es preparar los colores originales con &amp;lt;code&amp;gt;SetRGBBase&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;SetHSLBase&amp;lt;/code&amp;gt; y después aplicar el cambio. Los ejemplos utilizan las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt;, que trabajan con las copias de paleta de Dynamic Xtreme y evitan escribir direcciones de memoria.&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, estas ya se encargan de preparar los colores y completar su carga.&lt;br /&gt;
&lt;br /&gt;
En los ejemplos, prepara A en modo de 8 bits antes de llamar a las macros.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal de los efectos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Las macros de preparación de bases, mezcla, transición, conversión y &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; entran con A, X e Y de 8 bits. Sus variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; utilizan el mismo contrato. Las macros de concatenación tienen una entrada diferente, descrita en su apartado.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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 y memoria temporal|estado del CPU]].&lt;br /&gt;
* Pueden sobrescribir &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$45-$54&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8A-$8F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$D5-$D7&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; se lee con A de 16 bits. Prepara los operandos de memoria con el tamaño correspondiente.&lt;br /&gt;
* 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.&lt;br /&gt;
&lt;br /&gt;
==== Preparar los colores: SetRGBBase y SetHSLBase ====&lt;br /&gt;
&lt;br /&gt;
Antes de modificar los colores, necesitas una copia con la que calcular el efecto. &amp;lt;code&amp;gt;%SetRGBBase()&amp;lt;/code&amp;gt; prepara esa copia para efectos RGB; &amp;lt;code&amp;gt;%SetHSLBase()&amp;lt;/code&amp;gt; la prepara para HSL. Si los colores originales no cambiaron, puedes reutilizarla en los siguientes frames.&lt;br /&gt;
&lt;br /&gt;
En las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; solo indicas el primer color y cuántos colores quieres preparar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%SetRGBBaseDefault(offset, length)&lt;br /&gt;
%SetHSLBaseDefault(offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; es el número del primer color y &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; es la cantidad. Por ejemplo, &amp;lt;code&amp;gt;#$0081&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;#$000F&amp;lt;/code&amp;gt; seleccionan los 15 colores visibles de la paleta 8.&lt;br /&gt;
&lt;br /&gt;
Si necesitas elegir tú las direcciones donde leer y guardar los colores, utiliza las versiones completas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%SetRGBBase(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%SetHSLBase(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;%SetRGBBaseDefault(offset, length)&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%SetHSLBaseDefault(offset, length)&amp;lt;/code&amp;gt; leen de &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; y guardan el resultado en &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: preparar una paleta de sprites&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Paleta 8, sin incluir su primer color transparente.&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
    ; Para trabajar en HSL, utiliza esta variante en su lugar:&lt;br /&gt;
    ; %SetHSLBaseDefault(#$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$81&amp;lt;/code&amp;gt; es el segundo color de la paleta 8: la paleta comienza en el color &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; y se procesan los 15 siguientes.&lt;br /&gt;
&lt;br /&gt;
==== Mezclar colores: Mix y MixAndMerge ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Los parámetros &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; indican el color que quieres alcanzar, entre 0 y 31. Los parámetros &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#$7F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para RGB, los valores 1, 2 y 3 corresponden a rojo, verde y azul. Para HSL corresponden a tono, saturación y luminosidad.&lt;br /&gt;
&lt;br /&gt;
El final del nombre indica qué componentes se modifican:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! RGB !! HSL !! Componentes modificados&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;H&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;L&amp;lt;/code&amp;gt; || Uno.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GB&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SL&amp;lt;/code&amp;gt; || Dos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RGB&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HSL&amp;lt;/code&amp;gt; || Los tres.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada combinación está disponible como &amp;lt;code&amp;gt;Mix...&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixAndMerge...&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;MixAndMerge...Default&amp;lt;/code&amp;gt;. Por ejemplo: &amp;lt;code&amp;gt;%MixR()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%MixAndMergeR()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%MixAndMergeRDefault()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; omiten las direcciones.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%MixRGB(r1, r2, r3, v1, v2, v3, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%MixAndMergeRG(r1, r2, v1, v2, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%MixAndMergeLDefault(r3, v3, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo RGB: teñir de rojo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; Preparar los colores originales de la paleta 8.&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
    ; Acercar los tres componentes a un rojo puro, aproximadamente a la mitad.&lt;br /&gt;
    %MixAndMergeRGBDefault(#$40, #$40, #$40, #$1F, #$00, #$00, #$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los tres primeros valores &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt; indican la intensidad del cambio para rojo, verde y azul. Los siguientes, &amp;lt;code&amp;gt;#$1F, #$00, #$00&amp;lt;/code&amp;gt;, indican el rojo puro al que se acercarán. Los dos últimos seleccionan los 15 colores de la paleta 8.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo HSL: aclarar la paleta&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %SetHSLBaseDefault(#$0081, #$000F)&lt;br /&gt;
    %MixAndMergeLDefault(#$40, #$1F, #$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aquí solo cambia la luminosidad: &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt; aplica aproximadamente la mitad del cambio y &amp;lt;code&amp;gt;#$1F&amp;lt;/code&amp;gt; indica la luminosidad máxima. Este es un ejemplo independiente del anterior.&lt;br /&gt;
&lt;br /&gt;
==== Cambiar entre paletas: PaletteTransition ====&lt;br /&gt;
&lt;br /&gt;
Estas macros acercan cada color de la paleta original al color correspondiente de otra paleta. A diferencia de &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt;, cada color tiene su propio destino. Sirven, por ejemplo, para pasar de los colores normales de un sprite a una paleta de daño.&lt;br /&gt;
&lt;br /&gt;
Las variantes son &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransitionHSL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransitionRGBAndMerge&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PaletteTransitionHSLAndMerge&amp;lt;/code&amp;gt;. Las dos variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; también tienen versión &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteTransitionRGB(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%PaletteTransitionHSLAndMerge(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%PaletteTransitionRGBAndMergeDefault(r1, r2, r3, targetpal, targetpalbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;targetpal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;targetpalbnk&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: calcular un paso intermedio de una transición&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; Este ejemplo trabaja con los primeros 15 colores de la copia de paletas.&lt;br /&gt;
    %SetRGBBaseDefault(#$0000, #$000F)&lt;br /&gt;
    %PaletteTransitionRGBAndMergeDefault(#$40, #$40, #$40, #!PaletteMyTargetRGB, #!PaletteMyTargetRGB&amp;gt;&amp;gt;16, #$0000, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo supone que &amp;lt;code&amp;gt;!PaletteMyTargetRGB&amp;lt;/code&amp;gt; corresponde a una paleta de destino RGB generada al instalar un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; de transición. Su dirección queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_target&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyTarget&amp;lt;/code&amp;gt;. Para HSL se utiliza la paleta convertida a HSL y la macro correspondiente.&lt;br /&gt;
&lt;br /&gt;
==== Aplicar un efecto de un archivo: DoEffect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DoEffect()&amp;lt;/code&amp;gt; aplica un efecto de un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%DoEffect(effect, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%DoEffectAndMerge(effect, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%DoEffectAndMergeDefaultRGB(effect, offset, length)&lt;br /&gt;
%DoEffectAndMergeDefaultHSL(effect, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;effect&amp;lt;/code&amp;gt;: ID del efecto, como &amp;lt;code&amp;gt;#!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt;.&lt;br /&gt;
* El origen debe contener colores RGB o HSL separados, según el efecto elegido.&lt;br /&gt;
* &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; guarda el resultado con 3 bytes por color para poder seguir modificándolo.&lt;br /&gt;
* &amp;lt;code&amp;gt;DoEffectAndMerge&amp;lt;/code&amp;gt; guarda colores en formato de SNES. Las variantes &amp;lt;code&amp;gt;DefaultRGB&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DefaultHSL&amp;lt;/code&amp;gt; eligen la base correspondiente y escriben en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: aplicar un efecto RGB a la paleta 8&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
    %DoEffectAndMergeDefaultRGB(#!PaletteEffectIDMyEffect0, #$81, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; se genera desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. El número final identifica el efecto dentro del archivo. Si el efecto trabaja en HSL, prepara la base HSL y utiliza &amp;lt;code&amp;gt;%DoEffectAndMergeDefaultHSL()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Convertir entre RGB y HSL ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%RGBToHSL()&amp;lt;/code&amp;gt; convierte colores RGB a HSL y &amp;lt;code&amp;gt;%HSLToRGB()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%RGBToHSL(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%HSLToRGB(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: convertir la base RGB a HSL&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %RGBToHSL(#DX_PPU_CGRAM_BaseRGBPalette, #DX_PPU_CGRAM_BaseRGBPalette&amp;gt;&amp;gt;16, #DX_PPU_CGRAM_BaseHSLPalette, #DX_PPU_CGRAM_BaseHSLPalette&amp;gt;&amp;gt;16, #$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Combinar un efecto propio con el global ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; con &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, no se conserva X. A e Y pueden cambiar. Utilizan los temporales de efectos y &amp;lt;code&amp;gt;$F0-$F3&amp;lt;/code&amp;gt;. Conservan DBR y D. A diferencia de las demás macros de efectos, incluyen &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; y devuelven disponibilidad mediante carry, también cuando reutilizan un resultado anterior.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Suelen utilizarse después de &amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%ConcatenateRGBPaletteEffectToGlobal(sprite, paletteOption, palette)&lt;br /&gt;
%ConcatenateHSLPaletteEffectToGlobal(sprite, paletteOption, palette)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 recupera el índice del sprite desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 0 permite utilizar variables propias.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor de las opciones de paleta; activa el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; para incluir el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable que contiene la paleta asignada, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos.&lt;br /&gt;
* A de 16 bits: ID del efecto local RGB o HSL, según la macro.&lt;br /&gt;
* X de 8 bits: copia del valor de la paleta asignada.&lt;br /&gt;
* Y de 8 bits: conserva el valor devuelto por la asignación sin carga.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de los colores originales preparada por esa asignación.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: completar una asignación sin carga&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
; Llamar esta rutina con JSL después de asignar la paleta sin carga.&lt;br /&gt;
; Deben conservarse Y y $02-$04 de aquella llamada.&lt;br /&gt;
ApplyLocalEffect:&lt;br /&gt;
    LDA !NormalPalette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyEffect0&lt;br /&gt;
    %ConcatenateRGBPaletteEffectToGlobal(1, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; se genera desde un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. Para un efecto HSL, utiliza la macro HSL. Si usas Y para leer una tabla de efectos, guarda su valor con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; y recupéralo con &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; antes de concatenar.&lt;br /&gt;
&lt;br /&gt;
==== Elegir las direcciones y combinar varios efectos ====&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; 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:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;src&amp;lt;/code&amp;gt;: dónde leer los colores originales; &amp;lt;code&amp;gt;srcbnk&amp;lt;/code&amp;gt;: su banco.&lt;br /&gt;
* &amp;lt;code&amp;gt;dst&amp;lt;/code&amp;gt;: dónde guardar el resultado; &amp;lt;code&amp;gt;dstbnk&amp;lt;/code&amp;gt;: su banco. El destino debe ser un espacio de RAM que tu código pueda utilizar.&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: primer color que se procesará, contando desde 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt;: cantidad de colores que se procesarán.&lt;br /&gt;
&lt;br /&gt;
Para indicar una dirección fija, se utiliza &amp;lt;code&amp;gt;#Nombre&amp;lt;/code&amp;gt; para la dirección y &amp;lt;code&amp;gt;#Nombre&amp;gt;&amp;gt;16&amp;lt;/code&amp;gt; para su banco, como en el ejemplo de conversión RGB a HSL. También puedes pasar variables que contengan esos datos.&lt;br /&gt;
&lt;br /&gt;
El espacio necesario depende del paso que estés realizando:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Operación !! Lee !! Guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SetRGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SetHSLBase&amp;lt;/code&amp;gt; || Paleta normal: 2 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransition&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; sin &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| Variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Paleta normal: 2 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RGBToHSL&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;HSLToRGB&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si quieres aplicar dos efectos seguidos, el primero debe guardar sus colores separados, sin &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt;. El segundo lee ese resultado y utiliza &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; para dejar la paleta lista para cargarla. Si uno trabaja en RGB y el otro en HSL, convierte los colores entre ambos pasos.&lt;br /&gt;
&lt;br /&gt;
Las macros utilizan memoria temporal, entre otras las direcciones &amp;lt;code&amp;gt;$45-$50&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$51-$53&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8C&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8E&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$D5-$D7&amp;lt;/code&amp;gt;, según la operación. No guardes en ellas datos que necesites conservar después de la llamada.&lt;br /&gt;
&lt;br /&gt;
=== PPU ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué llamada elegir&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Necesitas… !! VRAM !! CGRAM&lt;br /&gt;
|-&lt;br /&gt;
| Indicar la dirección de origen y su banco por separado. || &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Indicar una dirección completa y dejar que la macro obtenga el banco. || &amp;lt;code&amp;gt;TransferToVRAMFromAddr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferToCGRAMFromAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Cargar un recurso completo registrado en Dynamic Xtreme. || &amp;lt;code&amp;gt;TransferResourceToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferResourceToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Cargar solo una cantidad de bytes de un recurso. || &amp;lt;code&amp;gt;TransferResourceToVRAMWithLenght&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferResourceToCGRAMWithLenght&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las versiones normales comprueban si la transferencia cabe dentro del límite de bytes del frame:&lt;br /&gt;
&lt;br /&gt;
* Carry activado: la transferencia quedó programada.&lt;br /&gt;
* Carry desactivado: no se programó porque superaría ese límite. Tu código puede intentarlo en otro frame.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Límites y condiciones de las transferencias&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Antes de preparar las entradas, ten en cuenta estos límites:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Presupuesto de bytes y capacidad de las listas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Límite !! Qué controla !! Valor predeterminado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;&lt;br /&gt;
| Cantidad total de bytes que se permite solicitar durante un frame. Se compara con &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, que acumula los bytes solicitados por los distintos recursos.&lt;br /&gt;
| &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt; bytes, compartidos entre las cargas de Dynamic Xtreme.&lt;br /&gt;
|-&lt;br /&gt;
| Lista de VRAM&lt;br /&gt;
| Cantidad de solicitudes que caben en sus tablas. Cada entrada utiliza dos bytes por tabla; &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; reserva la cantidad de bytes de cada una.&lt;br /&gt;
| &amp;lt;code&amp;gt;!VRAMTransferSize = 64&amp;lt;/code&amp;gt;: espacio para &#039;&#039;&#039;32 solicitudes&#039;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
| Lista de CGRAM&lt;br /&gt;
| Cantidad de solicitudes que caben en sus tablas. &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; determina la cantidad de entradas disponibles.&lt;br /&gt;
| &amp;lt;code&amp;gt;!CGRAMTransferSize = 64&amp;lt;/code&amp;gt;: espacio para &#039;&#039;&#039;64 solicitudes&#039;&#039;&#039;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Las macros normales comprueban &#039;&#039;&#039;el presupuesto de bytes&#039;&#039;&#039;, pero &#039;&#039;&#039;no comprueban si queda una entrada libre en la lista&#039;&#039;&#039;. 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.&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; omiten la comprobación del presupuesto de bytes y suman la cantidad solicitada a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Condiciones que debe cumplir la transferencia&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Dato !! Responsabilidad de tu código&lt;br /&gt;
|-&lt;br /&gt;
| Longitud&lt;br /&gt;
| Utiliza una cantidad de bytes &#039;&#039;&#039;mayor que cero y par&#039;&#039;&#039;. En DMA, &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; significa 65536 bytes, no una copia vacía. Las macros de PPU no comprueban estas condiciones.&lt;br /&gt;
|-&lt;br /&gt;
| Origen&lt;br /&gt;
| 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.&lt;br /&gt;
|-&lt;br /&gt;
| Origen en RAM&lt;br /&gt;
| 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.&lt;br /&gt;
|-&lt;br /&gt;
| Destino en VRAM&lt;br /&gt;
| La dirección se expresa en palabras de 2 bytes. Tanto el inicio como el final de la carga deben quedar dentro de &amp;lt;code&amp;gt;$0000–$7FFF&amp;lt;/code&amp;gt; y en el espacio gráfico que tu recurso puede utilizar. Por ejemplo, &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes desde &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; ocupan las palabras &amp;lt;code&amp;gt;$6000–$60FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Destino en CGRAM&lt;br /&gt;
| El destino indica el primer color. Cada color ocupa 2 bytes; la carga no debe pasar del color &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Por ejemplo, desde &amp;lt;code&amp;gt;$F1&amp;lt;/code&amp;gt; caben 15 colores, es decir, &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para cambiar colores conservando las copias de paleta de SMW y el estado de los efectos, utiliza [[#Cargar colores con TransferPalette|TransferPalette]]. Las transferencias de PPU a CGRAM solo programan la copia.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Estado de los registros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;, especialmente las de CGRAM.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* No incluyen &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. 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 &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; no devuelven un indicador de éxito en carry.&lt;br /&gt;
&lt;br /&gt;
Estas reglas también se aplican a las variantes &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;WithLenght&amp;lt;/code&amp;gt;: preparan los argumentos y expanden la misma transferencia.&lt;br /&gt;
&lt;br /&gt;
==== TransferToVRAM ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; programa una copia de gráficos desde ROM o RAM hacia VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToVRAM(VRAMOffset, ResourceAddr, ResourceBNK, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;VRAMOffset&amp;lt;/code&amp;gt;: dirección de destino en VRAM, expresada en palabras de 2 bytes. Por ejemplo, copiar &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes desde &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; ocupa las palabras &amp;lt;code&amp;gt;$6000-$60FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;ResourceAddr&amp;lt;/code&amp;gt;: dirección de origen dentro de su banco.&lt;br /&gt;
* &amp;lt;code&amp;gt;ResourceBNK&amp;lt;/code&amp;gt;: banco del origen.&lt;br /&gt;
* &amp;lt;code&amp;gt;Lenght&amp;lt;/code&amp;gt;: cantidad de bytes que se copiarán. Se conserva esta escritura del nombre porque así aparece en la macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: programar la carga de gráficos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToVRAM(#$6000, #!ResourceMyGraphics, #!ResourceMyGraphics&amp;gt;&amp;gt;16, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
    ; La copia se realizará en el próximo NMI.&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; es la dirección de un recurso registrado desde un DynamicInfo; queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;. La cantidad de bytes solicitada debe existir en ese recurso.&lt;br /&gt;
&lt;br /&gt;
==== TransferToVRAMFromAddr ====&lt;br /&gt;
&lt;br /&gt;
Hace la misma copia, pero recibe la dirección completa del origen. La macro separa su dirección y banco por ti.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToVRAMFromAddr(VRAMOffset, addr, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; se escribe sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;; los otros parámetros se entregan como en &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferToVRAMFromAddr(#$6000, !ResourceMyGraphics, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; se genera desde un recurso del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferResourceToVRAM y TransferResourceToVRAMWithLenght ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferResourceToVRAM(VRAMOffset, ResourceName)&lt;br /&gt;
%TransferResourceToVRAMWithLenght(VRAMOffset, ResourceName, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para un recurso cuyos defines sean &amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceMyGraphicsSize&amp;lt;/code&amp;gt;, escribe &amp;lt;code&amp;gt;&amp;quot;MyGraphics&amp;quot;&amp;lt;/code&amp;gt; como &amp;lt;code&amp;gt;ResourceName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: cargar el recurso completo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToVRAM(#$6000, &amp;quot;MyGraphics&amp;quot;)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: cargar solo sus primeros $0200 bytes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToVRAMWithLenght(#$6000, &amp;quot;MyGraphics&amp;quot;, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El nombre y el tamaño se obtienen de los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; al instalar los recursos del DynamicInfo. Utiliza el nombre normalizado: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;, eliminando los separadores y poniendo en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
==== TransferToCGRAM ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt; programa una copia de colores desde ROM o RAM hacia una paleta de SNES.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToCGRAM(CGRAMOffset, TableAddr, TableBNK, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;: número del primer color de destino, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Por ejemplo, la paleta 8 comienza en el color &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;TableAddr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TableBNK&amp;lt;/code&amp;gt;: dirección y banco de los colores que se van a copiar.&lt;br /&gt;
* &amp;lt;code&amp;gt;Lenght&amp;lt;/code&amp;gt;: cantidad de bytes. Cada color ocupa 2 bytes; 15 colores ocupan &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar los 15 colores visibles de la paleta 8&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToCGRAM(#$81, #DX_PPU_CGRAM_PaletteWriteMirror+$0102, #DX_PPU_CGRAM_PaletteWriteMirror&amp;gt;&amp;gt;16, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Este ejemplo toma el resultado de un efecto guardado en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;. El desplazamiento &amp;lt;code&amp;gt;$0102&amp;lt;/code&amp;gt; corresponde al color &amp;lt;code&amp;gt;$81&amp;lt;/code&amp;gt;, porque cada color ocupa 2 bytes. Se omite el primer color de la paleta, que es transparente en sprites.&lt;br /&gt;
&lt;br /&gt;
==== TransferToCGRAMFromAddr ====&lt;br /&gt;
&lt;br /&gt;
Hace la misma copia de colores, pero recibe la dirección completa del origen. Escribe &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToCGRAMFromAddr(CGRAMOffset, addr, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToCGRAMFromAddr(#$81, DX_PPU_CGRAM_PaletteWriteMirror+$0102, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== TransferResourceToCGRAM y TransferResourceToCGRAMWithLenght ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferResourceToCGRAM(CGRAMOffset, ResourceName)&lt;br /&gt;
%TransferResourceToCGRAMWithLenght(CGRAMOffset, ResourceName, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar un recurso completo de colores&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToCGRAM(#$80, &amp;quot;MyColors&amp;quot;)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar solo 15 colores&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToCGRAMWithLenght(#$81, &amp;quot;MyColors&amp;quot;, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Estos ejemplos suponen un recurso general de colores con los defines &amp;lt;code&amp;gt;!ResourceMyColors&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceMyColorsSize&amp;lt;/code&amp;gt;, generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; desde un DynamicInfo. Utiliza el nombre normalizado: &amp;lt;code&amp;gt;my_colors&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyColors&amp;lt;/code&amp;gt;. En el segundo ejemplo, el recurso debe comenzar con los 15 colores que se quieren copiar, sin anteponer el color transparente.&lt;br /&gt;
&lt;br /&gt;
==== Variantes Forced ====&lt;br /&gt;
&lt;br /&gt;
Todas las transferencias anteriores tienen una variante cuyo nombre comienza con &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;. Programa la copia aunque supere el límite de bytes del frame. La cantidad copiada también se suma al total de ese frame.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! VRAM !! CGRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferToVRAMFromAddr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferToCGRAMFromAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferResourceToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferResourceToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferResourceToVRAMWithLenght&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferResourceToCGRAMWithLenght&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Reciben los mismos parámetros que las versiones sin &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %ForcedTransferResourceToVRAM(#$6000, &amp;quot;MyGraphics&amp;quot;)&lt;br /&gt;
    ; No se comprueba el carry en esta variante.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt; corresponde al recurso &amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, generado desde el DynamicInfo. Se utiliza el nombre normalizado, como &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Matemáticas ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Prepara A en modo de 8 bits antes de llamarlas. Las macros no cambian por ti el tamaño de A, X o Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; todas las macros de esta categoría, incluidas &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;After...&amp;lt;/code&amp;gt;, 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 &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cómo escribir los argumentos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Mul&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Div&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MulAfterMul&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DivAfterDiv&amp;lt;/code&amp;gt; pegan el argumento directamente después de &amp;lt;code&amp;gt;LDA&amp;lt;/code&amp;gt;. Escribe el argumento entre comillas con un espacio al principio: &amp;lt;code&amp;gt;&amp;quot; #$05&amp;quot;&amp;lt;/code&amp;gt; produce &amp;lt;code&amp;gt;LDA #$05&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También puedes comenzar el argumento con &amp;lt;code&amp;gt;.b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;.l&amp;lt;/code&amp;gt; para elegir cómo se escribe el acceso a memoria. Por ejemplo, si &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; contiene el número que quieres multiplicar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot;.b $02&amp;quot;, &amp;quot; #$07&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esto genera &amp;lt;code&amp;gt;LDA.b $02&amp;lt;/code&amp;gt; para leer el primer número y &amp;lt;code&amp;gt;LDA #$07&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Las variantes con &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt;, además de &amp;lt;code&amp;gt;MulAfterDiv&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DivAfterMul&amp;lt;/code&amp;gt;, ya añaden un espacio antes de los argumentos. En ellas puedes escribir los valores normalmente, como &amp;lt;code&amp;gt;%MulW(#$05, #$07)&amp;lt;/code&amp;gt;. En la implementación actual no se pasan los sufijos &amp;lt;code&amp;gt;.b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;.l&amp;lt;/code&amp;gt; de esta misma manera a esas variantes, porque el espacio que añaden quedaría entre &amp;lt;code&amp;gt;LDA&amp;lt;/code&amp;gt; y el sufijo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;¿Qué significa la W?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El hardware necesita un pequeño tiempo para terminar el cálculo. Las macros con &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; incluyen esa espera: puedes leer el resultado inmediatamente después. Las versiones sin &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los resultados se leen mediante estos defines:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!MultiplicationResult&amp;lt;/code&amp;gt;: resultado de multiplicar, de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;!DivisionResult&amp;lt;/code&amp;gt;: cociente de la división, de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;!RemainderResult&amp;lt;/code&amp;gt;: resto de la división, de 16 bits.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Mul y MulW ====&lt;br /&gt;
&lt;br /&gt;
Multiplican dos valores de 8 bits y producen un resultado de 16 bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Mul(a, b)&lt;br /&gt;
%MulW(a, b)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; pueden ser valores inmediatos, como &amp;lt;code&amp;gt;#$06&amp;lt;/code&amp;gt;, o variables de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: 6 × 7 = 42&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %MulW(#$06, #$07)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $002A, es decir, 42&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La llamada sin espera sería &amp;lt;code&amp;gt;%Mul(&amp;quot; #$06&amp;quot;, &amp;quot; #$07&amp;quot;)&amp;lt;/code&amp;gt;. En ese caso no leas el resultado inmediatamente: ejecuta antes otro código que no utilice el hardware de multiplicación o división.&lt;br /&gt;
&lt;br /&gt;
==== Div y DivW ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Div(ah, al, b)&lt;br /&gt;
%DivW(ah, al, b)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;ah&amp;lt;/code&amp;gt;: byte alto del número que quieres dividir.&lt;br /&gt;
* &amp;lt;code&amp;gt;al&amp;lt;/code&amp;gt;: byte bajo del mismo número.&lt;br /&gt;
* &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;: número por el que divides, entre 1 y 255.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: 300 ÷ 7 = 42, con resto 6&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; 300 = $012C: byte alto $01, byte bajo $2C.&lt;br /&gt;
    %DivW(#$01, #$2C, #$07)&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $002A, es decir, 42&lt;br /&gt;
    LDA !RemainderResult         ; A = $0006&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
También puedes pasar una variable de 16 bits como dos argumentos: &amp;lt;code&amp;gt;%DivW(MiNumero+1, MiNumero, #$07)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;MiNumero&amp;lt;/code&amp;gt; representa aquí una variable definida por tu código.&lt;br /&gt;
&lt;br /&gt;
==== Continuar desde el resultado anterior ====&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;AfterMul&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;AfterDiv&amp;lt;/code&amp;gt; toman el resultado del cálculo anterior como primer número. Solo debes indicar el segundo número.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Macro !! Cálculo que realiza&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MulAfterMul(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MulWAfterMul(b)&amp;lt;/code&amp;gt; || Toma los 8 bits bajos del resultado de la multiplicación anterior y los multiplica por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MulAfterDiv(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MulWAfterDiv(b)&amp;lt;/code&amp;gt; || Toma los 8 bits bajos del cociente anterior y los multiplica por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DivAfterMul(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DivWAfterMul(b)&amp;lt;/code&amp;gt; || Divide el resultado completo de la multiplicación anterior por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DivAfterDiv(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DivWAfterDiv(b)&amp;lt;/code&amp;gt; || Divide el cociente completo de la división anterior por b.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La W sigue indicando que puedes leer el nuevo resultado inmediatamente después. Las variantes &amp;lt;code&amp;gt;After...&amp;lt;/code&amp;gt; ya incluyen la espera que necesitan para tomar el resultado del cálculo anterior.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dos multiplicaciones, (6 × 7) × 2 = 84&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot; #$06&amp;quot;, &amp;quot; #$07&amp;quot;)&lt;br /&gt;
    %MulWAfterMul(#$02)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $0054, es decir, 84&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dividir y después multiplicar, (100 ÷ 4) × 3 = 75&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Div(&amp;quot; #$00&amp;quot;, &amp;quot; #$64&amp;quot;, &amp;quot; #$04&amp;quot;)&lt;br /&gt;
    %MulWAfterDiv(#$03)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $004B, es decir, 75&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: multiplicar y después dividir, (20 × 15) ÷ 4 = 75&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot; #$14&amp;quot;, &amp;quot; #$0F&amp;quot;)&lt;br /&gt;
    %DivWAfterMul(#$04)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $004B, es decir, 75&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dos divisiones, (300 ÷ 3) ÷ 4 = 25&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Div(&amp;quot; #$01&amp;quot;, &amp;quot; #$2C&amp;quot;, &amp;quot; #$03&amp;quot;)&lt;br /&gt;
    %DivWAfterDiv(#$04)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $0019, es decir, 25&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En las multiplicaciones, el primer número siempre se limita a 8 bits. Si el resultado anterior era mayor que 255, &amp;lt;code&amp;gt;MulAfterMul&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;MulAfterDiv&amp;lt;/code&amp;gt; solo utilizará su byte bajo. Las divisiones de esta tabla sí toman el resultado anterior completo, de 16 bits.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_ASM_API&amp;diff=21384</id>
		<title>es/Dynamic Xtreme ASM API</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_ASM_API&amp;diff=21384"/>
		<updated>2026-10-25T17:23:56Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_ASM_API}}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Para aprender a organizar un sprite completo, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites]].&lt;br /&gt;
&lt;br /&gt;
== Variables y defines ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Los nombres de variables generales comienzan con &amp;lt;code&amp;gt;DX_&amp;lt;/code&amp;gt; y se escriben sin &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt;, por ejemplo &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;. Los defines como &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; sí llevan &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt;. Conserva la escritura exacta del nombre que aparece en el archivo.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Variables generales ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Contadores y cantidad de datos por frame ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; || 2 bytes || Cantidad de bytes que ya se programaron para transferir durante el frame actual. La actualizan las rutinas de carga.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; || 2 bytes || Límite de bytes que las cargas normales pueden programar en un frame. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; pueden superarlo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Poses cargadas en VRAM ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 byte || Cantidad de poses registradas actualmente en la caché.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 valores de 1 byte || Ayuda a encontrar las poses por su ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 128 valores de 2 bytes || ID de cada pose registrada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 128 valores de 2 bytes || Valor de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; de la última vez que se utilizó cada pose. Evita reemplazar gráficos que todavía se están mostrando.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 bytes compartidos || Describen las partes libres u ocupadas de VRAM. Son dos nombres para el mismo espacio de memoria.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 valores de 1 byte || Ayuda al sistema a recorrer las partes libres y ocupadas de VRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Paletas y efecto global ====&lt;br /&gt;
&lt;br /&gt;
Las tablas de 16 paletas utilizan el orden 0-F. En las tablas de valores de 2 bytes, la paleta 1 comienza en &amp;lt;code&amp;gt;+2&amp;lt;/code&amp;gt;, la 2 en &amp;lt;code&amp;gt;+4&amp;lt;/code&amp;gt;, y así sucesivamente.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 byte || Cada bit indica si una de las paletas 0-7 recibe el efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 byte || Cada bit indica si una de las paletas de sprites 8-F recibe el efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || ID del efecto global que se quiere aplicar. El valor 0 indica que no se aplica un efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Último efecto global revisado por el sistema. Se utiliza para detectar cambios.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 16 valores de 2 bytes || Último efecto global calculado para cada paleta. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; significa que aún no hay un resultado; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt;, que hay una actualización pendiente y se conserva el resultado anterior.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 16 valores de 2 bytes || ID asociado a cada paleta. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica que está libre; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; la excluye de la selección automática.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_Updated&amp;lt;/code&amp;gt; || 16 valores de 1 byte || Indica cuáles paletas ya se actualizaron durante el frame. Uso interno.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 byte || Registra qué paletas de sprites se utilizan con efectos. Uso interno del manejo de paletas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para reservar una paleta de sprites y evitar que la selección automática la utilice, su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; debe contener &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt;. Haz la reserva antes de que los sprites comiencen a solicitar paletas.&lt;br /&gt;
&lt;br /&gt;
==== Copias de colores y resultados de efectos ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 bytes || Copia de trabajo de las 256 entradas de color, con 2 bytes por color. Es la fuente de las variantes &amp;lt;code&amp;gt;SetRGBBaseDefault&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SetHSLBaseDefault&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 bytes || Colores originales separados en rojo, verde y azul: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 bytes || Colores originales separados en tono, saturación y luminosidad: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LocalEffectBuffer&amp;lt;/code&amp;gt; || 768 bytes || Espacio de trabajo para el resultado de un efecto local antes de combinarlo con el global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LocalEffectID&amp;lt;/code&amp;gt; || 16 valores de 2 bytes || ID del efecto local aplicado a cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 bytes || Colores resultantes en formato de SNES, con 2 bytes por color. Las variantes &amp;lt;code&amp;gt;AndMergeDefault&amp;lt;/code&amp;gt; escriben aquí.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Cada bit indica si ya se preparó la base RGB de una paleta de fondo o de sprites.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Lo mismo para las bases HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Cada bit indica si ya hay un resultado del efecto para esa paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LastPlayerPal&amp;lt;/code&amp;gt; || 2 bytes || Dirección de la última paleta del jugador procesada. El sistema la compara para detectar cambios.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Color fijo y primer color de la paleta ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 byte || Activa la participación en el efecto global: bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; para el color fijo y bit &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; para el color 0,0. &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; permite ambos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_BaseLoaded&amp;lt;/code&amp;gt; || 1 byte || Indica si se guardaron sus colores originales. Utiliza un bit por destino: &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_RGBBaseLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_ColorEffect_HSLBaseLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Indican si sus colores ya se prepararon en RGB o HSL, con los mismos bits.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Mirror&amp;lt;/code&amp;gt; || 2 bytes || Copia del color fijo que utiliza la actualización habitual del juego.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Base&amp;lt;/code&amp;gt; || 2 bytes || Color fijo original, antes de los efectos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_RGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_FixedColor_HSLBase&amp;lt;/code&amp;gt; || 3 bytes cada una || Color fijo original separado en RGB o HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Result&amp;lt;/code&amp;gt; || 2 bytes || Color fijo calculado después del efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Último efecto global calculado para el color fijo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Base&amp;lt;/code&amp;gt; || 2 bytes || Color 0,0 original.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_RGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_HSLBase&amp;lt;/code&amp;gt; || 3 bytes cada una || Color 0,0 original separado en RGB o HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Result&amp;lt;/code&amp;gt; || 2 bytes || Color 0,0 que se quiere mostrar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Último efecto global calculado para el color 0,0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Update&amp;lt;/code&amp;gt; || 1 byte || Un valor distinto de 0 solicita copiar &amp;lt;code&amp;gt;Result&amp;lt;/code&amp;gt; al color 0,0 durante NMI. Después de copiarlo, el sistema vuelve a poner esta variable en 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Transferencias pendientes ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || Cantidad de copias de gráficos pendientes, en 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || Cantidad de bytes de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || Destino de cada copia en VRAM, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || Dirección de origen de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || Banco de origen de cada copia. La tabla reserva 2 bytes por entrada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || Cantidad de copias de colores pendientes, en 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || Cantidad de bytes de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || Primer color de destino de cada copia, en valores de 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || Dirección de origen de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || Banco de origen de cada copia.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Jugador y Yoshi ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_Enable&amp;lt;/code&amp;gt; || 1 byte || 0 desactiva la carga de gráficos mediante este sistema; un valor distinto de 0 la activa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_Addr&amp;lt;/code&amp;gt; || 2 bytes || Dirección de inicio de los gráficos del jugador dentro del banco indicado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_BNK&amp;lt;/code&amp;gt; || 2 bytes reservados || Banco de origen de los gráficos del jugador. El banco se indica en el byte bajo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_Enable&amp;lt;/code&amp;gt; || 1 byte || 0 desactiva el manejo de paleta del jugador mediante este sistema; un valor distinto de 0 lo activa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_Addr&amp;lt;/code&amp;gt; || 2 bytes || Dirección de origen de la paleta del jugador.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_BNK&amp;lt;/code&amp;gt; || 1 byte || Banco de la paleta. Cuando es 0, la rutina toma la dirección de paleta que utiliza el juego.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_CustomPlayer&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_Dynamic_Player_LastCustomPlayer&amp;lt;/code&amp;gt; || 1 byte cada una || Variables reservadas para identificar al jugador personalizado y el anterior. La inicialización las pone en 0 y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;; actualmente no seleccionan por sí solas los gráficos de un personaje.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_VRAMEnable&amp;lt;/code&amp;gt; || 1 byte || 0 desactiva la carga de gráficos de Yoshi mediante este sistema; un valor distinto de 0 la activa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_Addr&amp;lt;/code&amp;gt; || 2 bytes || Dirección de inicio de los gráficos de Yoshi dentro de su banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_BNK&amp;lt;/code&amp;gt; || 1 byte || Banco de origen de los gráficos de Yoshi.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Dibujo y variables de sprites ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Drawing_InitialIndexHighPriority&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_Drawing_InitialIndexLowPriority&amp;lt;/code&amp;gt; ocupan 1 byte cada una y llevan la cuenta de las posiciones disponibles para dibujar sprites de prioridad alta o baja. &amp;lt;code&amp;gt;DX_Drawing_OAMMap&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Las variables individuales de sprites se definen en &amp;lt;code&amp;gt;DynamicXSpritesTables.asm&amp;lt;/code&amp;gt;. Los archivos &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; permiten utilizar los mismos nombres para los tres tipos:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Nombre para el sprite !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt; || Pose que se quiere mostrar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt; || Última pose que se consiguió y puede dibujarse. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; || Entrada donde el sistema tiene registrada la ubicación de sus gráficos. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt; || Volteo general, volteo adicional de la pose y volteo que se utiliza para dibujar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; || Paleta asignada: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; para la 8, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; para la 9, y así hasta &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; para la F. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; cuando se utiliza asignación dinámica.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; || Opciones &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: efecto global y elección de paleta o grupo de paletas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; || Modo de asignación: automático, manual o manual sin cargar colores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt; || Variante del sprite y última variante procesada al manejar su paleta. &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt; se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen,x&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SafeFrameLowByte,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!SafeFrameHighByte,x&amp;lt;/code&amp;gt; || Último frame en que se intentó solicitar una pose, para evitar repetir el trabajo durante el mismo frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AnimationIndex,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AnimationPoseIndex,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AnimationTimer,x&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!State,x&amp;lt;/code&amp;gt; || Variable para el estado o comportamiento del recurso.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada variable de esta tabla ocupa 1 byte por sprite. Hay &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; entradas para normales, 20 para cluster y 10 para extended. No utilices &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; como cantidad de entradas de cluster o extended.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Defines fijos ===&lt;br /&gt;
&lt;br /&gt;
Estos nombres representan configuraciones y direcciones conocidas. No son variables que cambian durante el juego.&lt;br /&gt;
&lt;br /&gt;
==== Compatibilidad con LoROM y SA-1 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; detecta el tipo de ROM y elige los valores correspondientes. Utiliza estos nombres para que tu código funcione en ambos casos.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! LoROM !! SA-1 !! Uso&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!sa1&amp;lt;/code&amp;gt; || 0 || 1 || Permite elegir código distinto según el tipo de ROM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!dp&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3000&amp;lt;/code&amp;gt; || Ajuste de las direcciones de página directa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!addr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; || Ajuste de las direcciones RAM que lo requieren, por ejemplo &amp;lt;code&amp;gt;$0100|!addr&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!rom&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$800000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$000000&amp;lt;/code&amp;gt; || Ajuste utilizado al acceder a direcciones del código original del juego.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; (12) || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; (22) || Cantidad de posiciones de sprites normales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MultiplicationResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4216&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2306&amp;lt;/code&amp;gt; || Dirección donde se lee el resultado de una multiplicación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DivisionResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4214&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2306&amp;lt;/code&amp;gt; || Dirección donde se lee el cociente de una división.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RemainderResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4216&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2308&amp;lt;/code&amp;gt; || Dirección donde se lee el resto de una división.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Otros defines utilizados para colocar las variables son &amp;lt;code&amp;gt;!normalBnk&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalCopyBNK&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt;. Normalmente basta con utilizar el nombre de cada variable &amp;lt;code&amp;gt;DX_...&amp;lt;/code&amp;gt;, sin calcular su dirección a partir de estos valores.&lt;br /&gt;
&lt;br /&gt;
==== Direcciones de gráficos en VRAM ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia !! Línea 0 !! Avance por línea !! Ejemplo&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG1LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG1Line1 = $0100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG2LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG2Line1 = $0900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG1LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG1Line1 = $1100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG3LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG3Line1 = $1900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG2LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG2Line1 = $2100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG3LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG3Line1 = $2900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LG1LineN&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!LG4LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4400&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4800&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4C00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!LG1Line1 = $4080&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SP1LineN&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!SP4LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6800&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$7000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$7800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!SP4Line1 = $7900&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Layer1Tilemap = $3000&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Layer2Tilemap = $3800&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
==== Configuraciones de espacio para poses dinámicas ====&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt; se entregan a &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt;. El nombre indica qué áreas de gráficos se permiten utilizar. &amp;lt;code&amp;gt;FirstHalf&amp;lt;/code&amp;gt; significa primera mitad y &amp;lt;code&amp;gt;SecondHalf&amp;lt;/code&amp;gt;, segunda mitad. Los nombres con &amp;lt;code&amp;gt;WithPlayer&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;WithDSX&amp;lt;/code&amp;gt; corresponden a las configuraciones previstas para esos casos.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Define&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$09&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP1WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP11WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3ndSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2andSP34&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$11&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$13&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$15&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3ndSP4WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$17&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2andSP34WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$19&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithPlayerAndDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithPlayerAndDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres de esta tabla se escriben exactamente como aparecen en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, incluidos nombres como &amp;lt;code&amp;gt;SecondHalfSSP4&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SP11WithPlayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Otras constantes ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! Valor o uso&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AN2Buffer1&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AN2Buffer2&amp;lt;/code&amp;gt; || Direcciones &amp;lt;code&amp;gt;$7EC100&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$7EAD00&amp;lt;/code&amp;gt; utilizadas para datos de animación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt;, dirección del buffer habitual de GFX32.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PlayerPaletteColor2To5&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$00B280&amp;lt;/code&amp;gt;, datos de los colores 2-5 de la paleta del jugador.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PlayerBasePalette&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$00B2C8&amp;lt;/code&amp;gt;, datos de la paleta base del jugador.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las opciones de instalación, como &amp;lt;code&amp;gt;!DynamicPoses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DrawingSystem&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!GraphicsChange&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalettesChange&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalettesEffects&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PlayerFeatures&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!YoshiFeatures&amp;lt;/code&amp;gt;, se incluyen desde &amp;lt;code&amp;gt;Options.asm&amp;lt;/code&amp;gt;. Sus valores indican qué funciones se instalaron; no se cambian durante el juego.&lt;br /&gt;
&lt;br /&gt;
=== Defines generados ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme crea estos defines al instalar los recursos y los añade a &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
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, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;my-sprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;my sprite&amp;lt;/code&amp;gt; se convierten en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. 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 &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Poses dinámicas y poses de dibujo ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia o ejemplo !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; || ID de unos gráficos de pose declarados en el DynamicInfo. Se utiliza para solicitar su carga con &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseMySprite000&amp;lt;/code&amp;gt; || Dirección ROM de esos gráficos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseMySprite000Size&amp;lt;/code&amp;gt; || Tamaño de esos gráficos en bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; || ID de una pose del DrawInfo. Se utiliza para dibujarla con &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;DrawStatic&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; || Distancia horizontal calculada desde el DrawInfo para saber cuándo el sprite deja de verse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; || Distancia vertical calculada desde el DrawInfo para la misma comprobación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; no se utiliza en lugar de un &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Paletas y efectos ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia o ejemplo !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteIDMyPalette&amp;lt;/code&amp;gt; || ID de una paleta declarada desde el DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; || Dirección ROM de sus colores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyPaletteSize&amp;lt;/code&amp;gt; || Tamaño de la paleta en bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; || Indica dónde comienza la lista de paletas de ese DynamicInfo. Se entrega a &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; y a sus variantes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; || ID de un efecto de &amp;lt;code&amp;gt;my_effect.paleffect&amp;lt;/code&amp;gt;. El número final identifica el efecto dentro del archivo; los IDs globales comienzan en 1.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyTargetRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PaletteMyTargetHSL&amp;lt;/code&amp;gt; || Dirección ROM de una paleta de destino convertida para una transición RGB o HSL. Se genera cuando un efecto necesita esa paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyTargetRGBSize&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PaletteMyTargetHSLSize&amp;lt;/code&amp;gt; || Tamaño en bytes de esas paletas convertidas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres de los ejemplos usan la misma normalización: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. Los defines se generan durante la instalación y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y buffers ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia o ejemplo !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt; || ID de un recurso general del DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt; || Dirección ROM de ese recurso.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt; || Tamaño del recurso en bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferIDMyBuffer&amp;lt;/code&amp;gt; || ID de un buffer insertado por la herramienta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferMyBuffer&amp;lt;/code&amp;gt; || Dirección del buffer insertado en la ROM; no es una variable temporal de RAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferMyBufferSize&amp;lt;/code&amp;gt; || Tamaño del buffer en bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres dependen de los recursos instalados. Se normalizan del mismo modo: &amp;lt;code&amp;gt;my_resource&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyResource&amp;lt;/code&amp;gt;. Consulta &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; para ver los nombres y valores de tu instalación.&lt;br /&gt;
&lt;br /&gt;
==== Cantidades y tablas generadas ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfDynamicPoses&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfPoses&amp;lt;/code&amp;gt; || Cantidad de poses dinámicas y de poses de dibujo instaladas, respectivamente.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfPalettes&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfResources&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfBuffers&amp;lt;/code&amp;gt; || Cantidad de paletas normales, recursos generales y buffers insertados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfPaletteEffects&amp;lt;/code&amp;gt; || 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 &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteTableSize&amp;lt;/code&amp;gt; || Cantidad total de entradas en las listas de paletas de los DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteIDTables&amp;lt;/code&amp;gt; || Dirección de la tabla de IDs de esas listas de paletas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAddrTables&amp;lt;/code&amp;gt; || Dirección de la tabla con las direcciones ROM de sus colores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsTypes&amp;lt;/code&amp;gt; || Tabla con el tipo de cada efecto instalado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsChannels1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsChannels2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsChannels3&amp;lt;/code&amp;gt; || Tablas con los valores de color de cada efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsRatios1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsRatios2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsRatios3&amp;lt;/code&amp;gt; || Tablas con los ratios que controlan cuánto se aplica cada cambio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferTable&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteTables&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsTable&amp;lt;/code&amp;gt; || Direcciones de las tablas que el parche publica para esos datos.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Defines de rutinas ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define o familia !! Uso&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AllowedGameMode&amp;lt;/code&amp;gt; || Comprueba si el modo de juego actual permite procesar las operaciones correspondientes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; || Elige las partes de VRAM disponibles para poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; || Solicita una pose por su ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; || Prepara las copias de gráficos de una pose a VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SetPropertyAndOffset&amp;lt;/code&amp;gt; || Obtiene la ubicación y propiedades de los gráficos de una pose dinámica para dibujarla.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Draw&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!Draw_Return&amp;lt;/code&amp;gt; || Entrada y punto de retorno utilizados por las rutinas de dibujo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RemapOamTile&amp;lt;/code&amp;gt; || Ajusta el número de tile para utilizar la ubicación real de los gráficos dinámicos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!IsValid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!XIsValid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!YIsValid&amp;lt;/code&amp;gt; || Comprobaciones utilizadas por el dibujo para decidir si un tile puede mostrarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AssignPalette&amp;lt;/code&amp;gt; || Selecciona el destino de una paleta según el modo de asignación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LoadPaletteOnBuffer&amp;lt;/code&amp;gt; || Carga datos de paleta en un espacio de trabajo para procesarlos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SetRGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!SetHSLBase&amp;lt;/code&amp;gt; || Prepara los colores para calcular efectos RGB o HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RGBToHSL&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!HSLToRGB&amp;lt;/code&amp;gt; || Convierte entre ambos sistemas de color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RGBMerge&amp;lt;/code&amp;gt; || Convierte colores RGB separados al formato de paleta de SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Mix...&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!MixAndMerge...&amp;lt;/code&amp;gt; || Aplica cambios a uno o varios componentes del color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalTransitionRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PalTransitionHSL&amp;lt;/code&amp;gt; || Calcula el cambio de una paleta a otra.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalTransitionAndMergeRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PalTransitionAndMergeHSL&amp;lt;/code&amp;gt; || Calcula la transición y deja el resultado en formato de SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DoEffect&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!DoEffectAndMerge&amp;lt;/code&amp;gt; || Aplica un efecto mediante su ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalFunctionRGB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalFunctionHSL&amp;lt;/code&amp;gt; y variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Nombres reservados para funciones de color que todavía no están implementadas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Routines&amp;lt;/code&amp;gt; es la dirección de la tabla desde la que se obtienen estas llamadas. No necesitas calcular sus posiciones para usar los defines publicados.&lt;br /&gt;
&lt;br /&gt;
== Estado del CPU y memoria temporal ==&lt;br /&gt;
&lt;br /&gt;
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: &#039;&#039;&#039;tamaño y contenido son cosas distintas&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Estas reglas se aplican a las llamadas de este artículo, salvo las excepciones indicadas en cada entrada:&lt;br /&gt;
&lt;br /&gt;
* Ejecuta el código en modo nativo, con el modo decimal desactivado. Las operaciones matemáticas del sistema utilizan números binarios.&lt;br /&gt;
* &#039;&#039;&#039;Direct page D:&#039;&#039;&#039; &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; en LoROM y &amp;lt;code&amp;gt;$3000&amp;lt;/code&amp;gt; en el contexto habitual de SA-1 Pack. Las direcciones cortas como &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; se interpretan respecto de esa base. Las llamadas no preparan ni cambian D por ti.&lt;br /&gt;
* &#039;&#039;&#039;Banco de datos DBR:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;$00-$3F&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;$80-$BF&amp;lt;/code&amp;gt;. 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. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; tiene un requisito específico de DBR, explicado en su entrada.&lt;br /&gt;
* 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.&lt;br /&gt;
* &#039;&#039;&#039;Flags:&#039;&#039;&#039; 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.&lt;br /&gt;
* &#039;&#039;&#039;Memoria temporal:&#039;&#039;&#039; 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.&lt;br /&gt;
* &#039;&#039;&#039;Pila:&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;PLP&amp;lt;/code&amp;gt; también reemplaza ese carry.&lt;br /&gt;
&lt;br /&gt;
== Rutinas para sprites ==&lt;br /&gt;
&lt;br /&gt;
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: &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt;. La ruta del include es relativa al archivo ASM del sprite.&lt;br /&gt;
&lt;br /&gt;
Los requisitos de DBR, D, flags y pila se explican en [[#Estado del CPU y memoria temporal|Estado del CPU y memoria temporal]]. La tabla siguiente distingue el tamaño de los registros de los valores que conservan.&lt;br /&gt;
&lt;br /&gt;
Para usar llamadas como &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, escribe su nombre directamente, como muestran los ejemplos. No añadas &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt; delante. Salvo que se indique lo contrario, X debe contener el número del slot que ocupa el sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y scratch de las llamadas para sprites&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Entra con X e Y en modo de 8 bits. El tamaño de A depende de la llamada:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Llamada !! A al entrar !! Registros al volver !! Scratch que puede sobrescribir&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;&lt;br /&gt;
| 8 bits.&lt;br /&gt;
| A cambia y queda en 8 bits. X e Y conservan su valor y tamaño.&lt;br /&gt;
| No utiliza scratch; modifica las tablas de Dynamic Xtreme descritas en su entrada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;&lt;br /&gt;
| 16 bits con &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; habilitado; 8 bits si está deshabilitado, sin utilizar el offset de tabla.&lt;br /&gt;
| A e Y pueden cambiar. X vuelve a cargarse desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; cuando se utiliza para el trabajo interno. La variante sin carga devuelve información en Y. Los tres quedan en 8 bits.&lt;br /&gt;
| &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$65-$67&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$D5&amp;lt;/code&amp;gt;, según el camino utilizado. Con efectos, también puede utilizar los temporales de efectos indicados más abajo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;&lt;br /&gt;
| 16 bits.&lt;br /&gt;
| A e Y pueden cambiar. X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. Los tres quedan en 8 bits.&lt;br /&gt;
| &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$47-$51&amp;lt;/code&amp;gt; cuando necesita preparar una carga nueva.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt;&lt;br /&gt;
| 16 bits.&lt;br /&gt;
| A e Y pueden cambiar. Si dibuja, X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; si no hay pose válida, conserva el X de entrada. Los tres quedan en 8 bits.&lt;br /&gt;
| &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$45-$4F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;. Con desplazamiento adicional, también &amp;lt;code&amp;gt;$8B-$8C&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;&lt;br /&gt;
| 8 bits.&lt;br /&gt;
| A e Y pueden cambiar. X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. Los tres quedan en 8 bits.&lt;br /&gt;
| &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; y los temporales utilizados por la carga de colores; también los de efectos cuando corresponde.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; y variante HSL&lt;br /&gt;
| 16 bits.&lt;br /&gt;
| A e Y pueden cambiar. Aunque X recibe una paleta al entrar, al volver contiene &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. Los tres quedan en 8 bits.&lt;br /&gt;
| Los temporales de efectos, &amp;lt;code&amp;gt;$05-$06&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$F0-$F3&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
PIXI mantiene &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; de los ejemplos pertenece a la rutina del sprite.&lt;br /&gt;
&lt;br /&gt;
=== RenderBox ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; 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).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen,x&amp;lt;/code&amp;gt;: distancias horizontal y vertical permitidas fuera de la pantalla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite está en pantalla o dentro de la distancia permitida fuera de sus bordes; se debe ejecutar la long routine.&lt;br /&gt;
* Carry desactivado: el sprite está demasiado lejos de la pantalla para dibujarse; se debe ejecutar la short routine.&lt;br /&gt;
&lt;br /&gt;
Cuando el sprite está demasiado lejos, establece &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Esto indica que deberá volver a obtener su paleta y su pose cuando se acerque a la pantalla. También guarda en &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt; el volteo que resulta de combinar &amp;lt;code&amp;gt;!GlobalFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip&amp;lt;/code&amp;gt;. En sprites normales actualiza además las variables que indican si está fuera de pantalla horizontal o verticalmente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
print &amp;quot;INIT &amp;quot;,pc&lt;br /&gt;
    LDA.b #!RenderBoxXDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderXDistanceOutOfScreen,x&lt;br /&gt;
    LDA.b #!RenderBoxYDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderYDistanceOutOfScreen,x&lt;br /&gt;
    ; Aquí va el resto de la inicialización del sprite&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
SpriteCode:&lt;br /&gt;
    !RenderBox&lt;br /&gt;
    BCS .LongRoutine&lt;br /&gt;
&lt;br /&gt;
.ShortRoutine&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    %SubOffScreen()&lt;br /&gt;
    ; Aquí va la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&lt;br /&gt;
.LongRoutine&lt;br /&gt;
    ; Aquí van el manejo de paletas, poses y dibujo&lt;br /&gt;
    ; y la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La llamada a &amp;lt;code&amp;gt;%SubOffScreen()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; se generan desde el DrawInfo y se guardan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. 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, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Si el sprite utiliza varios DrawInfo, utiliza la mayor distancia horizontal y la mayor distancia vertical entre ellos.&lt;br /&gt;
&lt;br /&gt;
=== PaletteAssignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; selecciona una paleta del DynamicInfo usando &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
Si el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; está activado (&amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;), también procesa los efectos globales de paleta correspondientes. Si está desactivado, la paleta queda excluida del efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cómo se elige la paleta&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; indica qué paleta de sprites se permite utilizar y si sus colores reciben el efecto global. Su formato es &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt;: 0 excluye la paleta del efecto global; 1 permite aplicarlo.&lt;br /&gt;
* &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt;: con asignación manual, selecciona una paleta entre 8 y F. &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; elige la 8, &amp;lt;code&amp;gt;001&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* Con asignación automática, &amp;lt;code&amp;gt;PPP = 000&amp;lt;/code&amp;gt; permite buscar entre las ocho paletas. Un valor &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; limita la búsqueda a las paletas 8-B; un valor &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; la limita a las C-F.&lt;br /&gt;
* Los cuatro bits bajos no se utilizan para estas opciones.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; decide quién elige el destino y si se cargan colores. Su formato es &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 00&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;): automático. Dynamic Xtreme elige una de las paletas permitidas y carga los colores del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 01&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;): manual. Utiliza la paleta indicada en &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; y carga los colores del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 10&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;): manual sin carga. Utiliza la paleta indicada en &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; con los colores que ya tiene el nivel.&lt;br /&gt;
&lt;br /&gt;
En sprites normales, &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; es &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; es &amp;lt;code&amp;gt;!ExtraProp2,x&amp;lt;/code&amp;gt;. Lo habitual es usar el primer Extra Byte con formato &amp;lt;code&amp;gt;EPPPVVVV&amp;lt;/code&amp;gt; y copiar sus cuatro bits bajos a &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, con asignación manual, &amp;lt;code&amp;gt;!PaletteOption,x = $A0&amp;lt;/code&amp;gt; utiliza la paleta A y permite el efecto global. Si &amp;lt;code&amp;gt;!Version,x = 1&amp;lt;/code&amp;gt;, carga en ella la segunda paleta de la lista del DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; correspondiente al DynamicInfo que contiene las paletas.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;: índice de la paleta dentro de la tabla.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: última versión procesada. Se compara con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; para detectar cambios y debe inicializarse en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;: selección de paleta y participación en el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt;: asignación automática, manual o manual sin carga.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite puede dibujarse con la paleta asignada.&lt;br /&gt;
* Carry desactivado: el sprite todavía no tiene una paleta lista para dibujar.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta asignada, con valores de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos para las paletas 8-F.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: se actualiza con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; cuando se procesa la nueva asignación.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignment&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre del recurso se normaliza en PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== PaletteAssignmentNoUpload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; elige la paleta igual que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
El bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;) 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 &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; elige la paleta del DynamicInfo: 0 para la primera, 1 para la segunda, etc. &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: 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, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; elige el destino automáticamente, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; usa el indicado en PPP y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt;: mismas opciones que en &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: última versión procesada, utilizada para detectar cambios respecto de &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;. Debe inicializarse en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite tiene una paleta asignada; desactivado si no pudo obtenerse.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta asignada.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: se actualiza con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; cuando se procesa la nueva asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: número que identifica la paleta elegida del DynamicInfo, cuando se utiliza un modo que carga sus colores.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base en ROM.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    ; Aquí se prepara y concatena el efecto.&lt;br /&gt;
    ; Conserva Y y la dirección de $02-$04 para esa llamada.&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; dice qué paleta del DynamicInfo se eligió; &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; dice cuál de las paletas 8-F utilizará el sprite para dibujarse. Los datos de &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;, eliminando los separadores.&lt;br /&gt;
&lt;br /&gt;
=== Upload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; consigue los gráficos de la pose que el sprite quiere mostrar. La pose se selecciona sumando &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico base.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt;: índice que se suma al ID base.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt;: volteos que se combinarán para dibujar.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* Carry desactivado: el sprite todavía no tiene una pose disponible.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt;: estado de la pose disponible para dibujar.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    !Upload&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== UploadWithoutPoseOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; solicita directamente el ID dinámico entregado en A, sin sumarle &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;. Como &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, reutiliza los gráficos si ya están en VRAM y puede seguir mostrando la pose anterior mientras no consiga cargar la nueva.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: existe &amp;lt;code&amp;gt;%DXExtendedUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;, pero actualmente &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; no publica el alias &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico exacto.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt;: volteos del sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite tiene una pose disponible para dibujar; desactivado si todavía no tiene ninguna.&lt;br /&gt;
* Guarda la pose que se puede dibujar en &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt; y la ubicación de sus gráficos en &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;, igual que &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite003&lt;br /&gt;
    !UploadWithoutPoseOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite003&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== DXDraw ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; dibuja una pose utilizando los gráficos dinámicos disponibles para el sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID de la pose de dibujo.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;): propiedades adicionales, con formato &amp;lt;code&amp;gt;YXCC----&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;): prioridad máxima de los tiles; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; máxima, &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; alta, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; propia del tipo de sprite y &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; mínima.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;: paleta, volteo y ubicación de los gráficos disponibles.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose en pantalla. Si &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no dibuja. A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDraw&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, las poses deben estar en el mismo orden en el DrawInfo y el DynamicInfo. Se utiliza &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; porque indica qué pose se puede dibujar: si la nueva todavía no se pudo cargar, seguirá mostrando la anterior.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres de recurso y pose se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Este ID de dibujo es distinto de los IDs &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; del DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
=== DXDrawWithOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Las mismas entradas de &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;): desplazamiento horizontal de 8 bits con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;): desplazamiento vertical de 8 bits con signo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja igual que &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;, pero suma los desplazamientos que preparaste. Un valor positivo en &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; mueve el dibujo a la derecha; en &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt;, hacia abajo. Los valores negativos lo mueven a la izquierda o hacia arriba.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$08&lt;br /&gt;
    STA !XOffsetParam&lt;br /&gt;
    LDA #$F8&lt;br /&gt;
    STA !YOffsetParam&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDrawWithOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo desplaza el dibujo 8 píxeles a la derecha y 8 hacia arriba. &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; el nombre se normaliza en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ReplacePalette ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Suele utilizarse después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;: primero se asigna la paleta sin cargar sus colores y después se reemplazan por los que quieres mostrar. Antes de llamar a &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, coloca en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; la dirección de los nuevos colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* A en modo de 8 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de la nueva paleta en BGR555.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta ya asignada.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;: participación en el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta; si los nuevos colores todavía no están listos, se conservan los anteriores.&lt;br /&gt;
* Carry desactivado: la paleta todavía no tiene colores listos para dibujar.&lt;br /&gt;
&lt;br /&gt;
Mantiene el mismo ID de paleta, pero solicita cambiar sus colores. Al marcar que el efecto debe volver a calcularse, utiliza &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; si nunca se habían obtenido colores para dibujar, o &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; si puede seguir mostrando los anteriores mientras prepara los nuevos.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ReplaceSpritePalette:&lt;br /&gt;
    ; Ejecutar cuando se necesite cambiar una paleta ya asignada.&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;8&lt;br /&gt;
    STA $03&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
    !ReplacePalette&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyAlternatePalette&amp;lt;/code&amp;gt; es la dirección de una paleta insertada desde los recursos declarados en un DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_alternate_palette&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyAlternatePalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ConcatenateRGBPaletteEffectToGlobal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, y después aplica el global sobre ese resultado. Llámala después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, que deja preparada la paleta original.&lt;br /&gt;
&lt;br /&gt;
El uso habitual es asignar primero la paleta con &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; y, si el carry está activado, llamar a esta rutina para aplicar los efectos y completar la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID del efecto local RGB.&lt;br /&gt;
* X de 8 bits: copia aquí el valor de &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;LDA !Palette,x&amp;lt;/code&amp;gt; seguido de &amp;lt;code&amp;gt;TAX&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
* Y de 8 bits: conserva el valor que dejó &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;. El valor 1 obliga a calcular de nuevo el efecto; 0 permite reutilizar el resultado anterior si no cambió nada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base BGR555 preparada por la asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;: el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; debe estar activado para combinar con el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta. Si el nuevo efecto todavía no está listo, se sigue mostrando el anterior.&lt;br /&gt;
* Carry desactivado: todavía no hay colores listos para dibujar esa paleta.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyRGBEffect0&lt;br /&gt;
    !ConcatenateRGBPaletteEffectToGlobal&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y &amp;lt;code&amp;gt;!PaletteEffectIDMyRGBEffect0&amp;lt;/code&amp;gt; desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. Ambos quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Si se necesita Y para seleccionar el efecto mediante una tabla, conserva su valor con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; y restáuralo con &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; antes de concatenar.&lt;br /&gt;
&lt;br /&gt;
=== ConcatenateHSLPaletteEffectToGlobal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt; permite que la paleta del sprite tenga un efecto HSL propio, como &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, y siga siendo afectada por el efecto global. Primero aplica el efecto local y después el global. Llámala después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, que deja preparada la paleta original.&lt;br /&gt;
&lt;br /&gt;
El uso habitual es asignar primero la paleta con &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; y, si el carry está activado, llamar a esta rutina para aplicar los efectos y completar la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID del efecto local HSL.&lt;br /&gt;
* X de 8 bits: copia aquí el valor de &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;LDA !Palette,x&amp;lt;/code&amp;gt; seguido de &amp;lt;code&amp;gt;TAX&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
* Y de 8 bits: conserva el valor que dejó &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;. El valor 1 obliga a calcular de nuevo el efecto; 0 permite reutilizar el resultado anterior si no cambió nada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base BGR555 preparada por la asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;: el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; debe estar activado para combinar con el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta. Si el nuevo efecto todavía no está listo, se sigue mostrando el anterior.&lt;br /&gt;
* Carry desactivado: todavía no hay colores listos para dibujar esa paleta.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyHSLEffect0&lt;br /&gt;
    !ConcatenateHSLPaletteEffectToGlobal&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y &amp;lt;code&amp;gt;!PaletteEffectIDMyHSLEffect0&amp;lt;/code&amp;gt; desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. Quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y utilizan nombres normalizados en PascalCase: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra. Conserva Y con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; si lo utilizas temporalmente para seleccionar el efecto.&lt;br /&gt;
&lt;br /&gt;
Ambas variantes de concatenación realizan las conversiones necesarias si el efecto local y el global utilizan espacios de color diferentes. Consulta [[es/Dynamic_Xtreme_files_and_formats#Tipos_de_efectos|Tipos de efectos]] para identificar los efectos RGB y HSL.&lt;br /&gt;
&lt;br /&gt;
== Rutinas y Macros Generales ==&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!NormalPoseIndex,x&amp;lt;/code&amp;gt;, escríbelo entre comillas para que Asar lo lea como un solo argumento. Utiliza &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; al entregar un valor inmediato, como &amp;lt;code&amp;gt;#$04&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Aplica también las reglas de [[#Estado del CPU y memoria temporal|DBR, direct page, flags y pila]]. Los contratos de cada familia indican qué registros y temporales debes guardar si necesitas conservarlos.&lt;br /&gt;
&lt;br /&gt;
=== Poses dinámicas ===&lt;br /&gt;
&lt;br /&gt;
==== DynamicPoseSpaceConfig ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt; y retorna con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; elige qué partes de la memoria gráfica (VRAM) puede usar Dynamic Xtreme para cargar poses dinámicas. Normalmente se llama desde el &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; de UberASM al entrar al nivel.&lt;br /&gt;
&lt;br /&gt;
Los defines con las configuraciones disponibles se encuentran en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, bajo los nombres &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 8 bits: una de las configuraciones &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus valores van de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicSpaceConfigSP4&amp;lt;/code&amp;gt; es una constante publicada en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permite utilizar SP4. Otras opciones incluyen &amp;lt;code&amp;gt;!DynamicSpaceConfigSP3&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt;. Selecciona una región que no se superponga con los gráficos estáticos utilizados por el nivel.&lt;br /&gt;
&lt;br /&gt;
==== DefineDynamicSpaceConfig ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DefineDynamicSpaceConfig()&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%DefineDynamicSpaceConfig(init, end, restricted)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;: ID del primer bloque de 16×16 del espacio.&lt;br /&gt;
* &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;: ID del último bloque de 16×16 del espacio. Ambos extremos se incluyen.&lt;br /&gt;
* &amp;lt;code&amp;gt;restricted&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; permite utilizar ese espacio para poses dinámicas; &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; lo restringe y el sistema no puede elegirlo para cargar poses.&lt;br /&gt;
&lt;br /&gt;
Los tres parámetros son constantes utilizadas al ensamblar y se escriben sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;. El primer bloque debe ser menor o igual que el último, y ambos deben estar entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt;. Por ejemplo, &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; hasta &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt; incluye 32 bloques.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cómo se numeran los bloques&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Para esta configuración, el espacio de gráficos de sprites se considera una cuadrícula de &#039;&#039;&#039;128×256 píxeles&#039;&#039;&#039;. La mitad superior, de 128×128, corresponde a SP1 y SP2; la mitad inferior, también de 128×128, corresponde a SP3 y SP4.&lt;br /&gt;
&lt;br /&gt;
La cuadrícula se divide en bloques de 16×16: hay &#039;&#039;&#039;8 bloques por fila y 16 filas&#039;&#039;&#039;, 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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Fila en píxeles !! Col. 0 !! Col. 1 !! Col. 2 !! Col. 3 !! Col. 4 !! Col. 5 !! Col. 6 !! Col. 7&lt;br /&gt;
|-&lt;br /&gt;
! 0–15&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 16–31&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$09&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 32–47&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$11&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$13&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$15&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$17&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 48–63&lt;br /&gt;
| &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$19&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 64–79&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$21&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$22&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$23&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$24&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$26&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$27&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 80–95&lt;br /&gt;
| &amp;lt;code&amp;gt;$28&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$29&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 96–111&lt;br /&gt;
| &amp;lt;code&amp;gt;$30&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$31&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$32&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$33&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$34&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$35&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$36&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$37&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 112–127&lt;br /&gt;
| &amp;lt;code&amp;gt;$38&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$39&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 128–143&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$41&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$42&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$43&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$44&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$45&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$46&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$47&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 144–159&lt;br /&gt;
| &amp;lt;code&amp;gt;$48&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$49&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 160–175&lt;br /&gt;
| &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$51&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$53&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$54&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$55&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$56&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$57&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 176–191&lt;br /&gt;
| &amp;lt;code&amp;gt;$58&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$59&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 192–207&lt;br /&gt;
| &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$61&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$62&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$63&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$64&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$65&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$66&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$67&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 208–223&lt;br /&gt;
| &amp;lt;code&amp;gt;$68&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$69&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 224–239&lt;br /&gt;
| &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$71&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$72&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$73&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$74&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$75&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$76&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$77&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! 240–255&lt;br /&gt;
| &amp;lt;code&amp;gt;$78&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$79&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada columna ocupa 16 píxeles de ancho. Estos IDs identifican posiciones de bloques de 16×16 en el mapa; no son los TileCodes de 8×8 que utiliza el DrawInfo.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Sección !! Bloques !! Posición en la cuadrícula&lt;br /&gt;
|-&lt;br /&gt;
| SP1 || &amp;lt;code&amp;gt;$00–$1F&amp;lt;/code&amp;gt; || Primeras cuatro filas.&lt;br /&gt;
|-&lt;br /&gt;
| SP2 || &amp;lt;code&amp;gt;$20–$3F&amp;lt;/code&amp;gt; || Siguientes cuatro filas.&lt;br /&gt;
|-&lt;br /&gt;
| SP3 || &amp;lt;code&amp;gt;$40–$5F&amp;lt;/code&amp;gt; || Siguientes cuatro filas.&lt;br /&gt;
|-&lt;br /&gt;
| SP4 || &amp;lt;code&amp;gt;$60–$7F&amp;lt;/code&amp;gt; || Últimas cuatro filas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplos del parche&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Estas configuraciones utilizan los mismos rangos que las opciones predefinidas del parche. Colócalas en el &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; de UberASM, antes de que los sprites soliciten sus poses.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Utilizar solamente SP4:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    ; SP1, SP2 y SP3 restringidos.&lt;br /&gt;
    %DefineDynamicSpaceConfig($00, $5F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; SP4 disponible para poses dinámicas.&lt;br /&gt;
    %DefineDynamicSpaceConfig($60, $7F, $00)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Utilizar solamente SP3:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    ; SP1 y SP2 restringidos.&lt;br /&gt;
    %DefineDynamicSpaceConfig($00, $3F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; SP3 disponible para poses dinámicas.&lt;br /&gt;
    %DefineDynamicSpaceConfig($40, $5F, $00)&lt;br /&gt;
&lt;br /&gt;
    ; SP4 restringido.&lt;br /&gt;
    %DefineDynamicSpaceConfig($60, $7F, $80)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Utilizar SP3 y SP4:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    ; SP1 y SP2 restringidos.&lt;br /&gt;
    %DefineDynamicSpaceConfig($00, $3F, $80)&lt;br /&gt;
&lt;br /&gt;
    ; SP3 y SP4 disponibles como un solo espacio.&lt;br /&gt;
    %DefineDynamicSpaceConfig($40, $7F, $00)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cada ejemplo es una alternativa: utiliza una configuración completa, cubriendo los bloques &amp;lt;code&amp;gt;$00–$7F&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* Escribe la configuración en &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt;, en los extremos del espacio indicado. No utiliza scratch.&lt;br /&gt;
* No carga gráficos ni mueve poses que ya estén en VRAM. Utilízala para preparar el espacio al entrar al nivel.&lt;br /&gt;
* No devuelve éxito o fallo en carry y no incluye &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;: el código continúa después de cada llamada. El &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; de los ejemplos termina el &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; de UberASM.&lt;br /&gt;
&lt;br /&gt;
==== TakeDynamicRequest ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$47-$51&amp;lt;/code&amp;gt; al preparar una carga nueva. Conserva DBR y D, tanto en éxito como en fallo. Se llama con &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt; y retorna con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !TakeDynamicRequest&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Y de 16 bits: ID exacto de la pose dinámica.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RequestPose:&lt;br /&gt;
    REP #$10&lt;br /&gt;
    LDY #!DynamicPoseIDMySprite000&lt;br /&gt;
    JSL !TakeDynamicRequest&lt;br /&gt;
    BCC .Unavailable&lt;br /&gt;
&lt;br /&gt;
    ; X contiene el índice hash de la pose solicitada.&lt;br /&gt;
    ; Aquí tu código puede guardar ese índice para dibujar la pose.&lt;br /&gt;
RTS&lt;br /&gt;
.Unavailable&lt;br /&gt;
    ; Aquí se maneja la falta de recursos.&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores y escribiendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== DynamicRoutine ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;$00-$0B&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$47-$51&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt; corresponde a los dos bytes de &amp;lt;code&amp;gt;$02-$03&amp;lt;/code&amp;gt; de la direct page. Conserva D y no cambia DBR: debes preparar el banco de las tablas antes de llamarla. Se llama con &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt; y retorna con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !DynamicRoutine&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; prepara esos datos antes de llamarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Datos que necesita la llamada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt;: variable interna de 16 bits que contiene el ID de la pose que se va a copiar.&lt;br /&gt;
* 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.&lt;br /&gt;
&lt;br /&gt;
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. &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; realiza ambas tareas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo de funcionamiento&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Cuando un sprite solicita una pose que todavía no está en VRAM, &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; busca dónde colocarla. Después guarda su ID en &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt; y llama a &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; con la posición elegida en A. Esta última prepara la copia de los gráficos; el NMI ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
Para cargar una pose desde el código de un sprite, utiliza &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. Si necesitas hacer la solicitud directamente mediante su ID, utiliza &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt;. Llamar a &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; requiere preparar también la variable interna del ID, el banco de datos y el espacio de destino descritos arriba.&lt;br /&gt;
&lt;br /&gt;
==== GeneralUpload ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;, X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; con &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, no se conserva X. Puede sobrescribir &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$47-$51&amp;lt;/code&amp;gt;, incluidos los temporales de una solicitud nueva. Conserva DBR y D. Incluye &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;: llama con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt; a la rutina que contiene la macro.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%GeneralUpload(Pose16, checkLast, sprite, flip, safeCheck, withoutOffset,&lt;br /&gt;
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,&lt;br /&gt;
    globalFlip, localFlip, lastFlip)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La firma anterior muestra el orden de los parámetros; escribe la llamada en una sola línea.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Pose16&amp;lt;/code&amp;gt;: 0 utiliza índices de pose de 8 bits; 1 utiliza índices de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt;: 1 permite seguir dibujando la pose anterior si no se pudo obtener la nueva; 0 desactiva esa opción.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 0 para usar variables propias sin recuperar el índice del sprite; 1 para trabajar con las tablas del sprite, recuperando X desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 2 funciona como 1, pero solicita la pose sin comparar ni cambiar &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;flip&amp;lt;/code&amp;gt;: 1 combina &amp;lt;code&amp;gt;globalFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;localFlip&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;; 0 omite esa actualización.&lt;br /&gt;
* &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt;: 1 evita repetir la solicitud en el mismo frame utilizando &amp;lt;code&amp;gt;safeLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;safeHigh&amp;lt;/code&amp;gt;; 0 omite la comprobación.&lt;br /&gt;
* &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;: 0 suma &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt; al ID base; 1 utiliza directamente el ID recibido.&lt;br /&gt;
* &amp;lt;code&amp;gt;safeLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;safeHigh&amp;lt;/code&amp;gt;: variables que guardan los bytes bajo y alto del frame de la solicitud. Se escriben incluso cuando &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; es 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt;: variable del índice de pose deseado.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;: variable del último índice de pose disponible.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;: variable que identifica la entrada donde Dynamic Xtreme guarda la ubicación de los gráficos en VRAM. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; indica que todavía no hay gráficos disponibles.&lt;br /&gt;
* &amp;lt;code&amp;gt;globalFlip&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;localFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variables del volteo global, local y efectivo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada adicional&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico base o exacto, según &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Para &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; debe contener el índice del sprite.&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt;, la macro solicita la pose aunque &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sean iguales, y deja &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sin modificar. Si consigue los gráficos, guarda su ubicación en &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;. Si la solicitud falla y &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; es 1, puede seguir usando los gráficos anteriores. &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; sigue controlando si se permite repetir la solicitud durante el mismo frame.&lt;br /&gt;
&lt;br /&gt;
Este valor 2 no cambia el tamaño de los índices. Para utilizar variables de índice de 16 bits se selecciona &amp;lt;code&amp;gt;Pose16 = 1&amp;lt;/code&amp;gt;. El ID dinámico entregado en A siempre es de 16 bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Devuelve el carry activado cuando hay una pose disponible para dibujar: la solicitada o la anterior si &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; al final; colócala al final de una rutina llamada con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %GeneralUpload(0, 1, 1, 1, 1, 0, &amp;quot;!NormalSafeFrameLowByte,x&amp;quot;, &amp;quot;!NormalSafeFrameHighByte,x&amp;quot;, &amp;quot;!NormalPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalGlobalFlip,x&amp;quot;, &amp;quot;!NormalLocalFlip,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las tablas de un sprite normal y un índice de pose de 8 bits. &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; el nombre se normaliza en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Upload (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; utiliza el mismo contrato de [[#GeneralUpload|GeneralUpload]], con &amp;lt;code&amp;gt;Pose16 = 0&amp;lt;/code&amp;gt;. A entra en 16 bits, X/Y en 8 bits, y los tres quedan en 8 bits. El valor de &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt; determina si X vuelve a cargarse desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. La macro incluye &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%Upload()&amp;lt;/code&amp;gt; es la variante de &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; para índices de pose de 8 bits. No debe confundirse con el alias para sprites &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Upload(sprite, checkLast, flip, safeCheck, withoutOffset,&lt;br /&gt;
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,&lt;br /&gt;
    globalFlip, localFlip, lastFlip)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Recibe los mismos datos que &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt;, pero los índices guardados en las variables siempre son de 8 bits. La macro ya incluye el &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
El parámetro &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt; también admite 2: omite la comparación con &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; y no actualiza esa variable, pero sí actualiza &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt; al obtener la pose. No habilita índices de 16 bits; para eso se utiliza &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;Pose16 = 1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sin modificar, el código del sprite puede controlar ese cambio.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %Upload(1, 1, 1, 1, 0, &amp;quot;!NormalSafeFrameLowByte,x&amp;quot;, &amp;quot;!NormalSafeFrameHighByte,x&amp;quot;, &amp;quot;!NormalPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalGlobalFlip,x&amp;quot;, &amp;quot;!NormalLocalFlip,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; es generado desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpriteUpload ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; utiliza el contrato de [[#GeneralUpload|GeneralUpload]] con &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;. A entra en 16 bits y X/Y en 8 bits. Al volver, X contiene &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; A e Y pueden cambiar y los tres quedan en 8 bits. Comparte sus scratch y termina con &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpriteUpload(withoutOffset, type)&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;: 0 suma &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; al ID base; 1 utiliza el ID exacto.&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A de 16 bits: ID dinámico.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* Tablas de poses y volteo de Dynamic Xtreme del tipo seleccionado, inicializadas como en las rutinas &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %StandardSpriteUpload(0, &amp;quot;Normal&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;, eliminando los separadores.&lt;br /&gt;
&lt;br /&gt;
=== Dibujo de poses ===&lt;br /&gt;
&lt;br /&gt;
Las macros de esta categoría terminan la rutina que las contiene mediante &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;. Los ejemplos deben llamarse con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;. A debe contener el ID de dibujo con 16 bits; &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;) se preparan igual que para &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Draw ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; entra con A de 16 bits y X/Y de 8 bits. A e Y pueden cambiar. Con &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; al preparar un dibujo válido; con &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, no se conserva el X inicial. Si no hay pose válida, X no cambia. Los tres registros quedan en 8 bits. Puede sobrescribir &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$45-$4F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;; con &amp;lt;code&amp;gt;offset = 1&amp;lt;/code&amp;gt;, también &amp;lt;code&amp;gt;$8B-$8C&amp;lt;/code&amp;gt;. Conserva DBR y D. Incluye &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%Draw()&amp;lt;/code&amp;gt; dibuja una pose dinámica. En la llamada indicas qué gráficos usar, su paleta, su volteo y la posición donde quieres dibujarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Draw(offset, sprite, lastPoseHashIndex, lastFlip, palette, xl, xh, yl, yh)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 utiliza las coordenadas entregadas; 1 añade &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;), de 8 bits con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 recupera el índice del sprite en X desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; antes de leer su paleta y posición; 0 omite ese paso.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;: variable que identifica dónde están registrados los gráficos de la pose en Dynamic Xtreme. Si contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no se dibuja.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variable o valor que indica el volteo con el que se dibujará.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de la paleta; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; selecciona la 8, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* &amp;lt;code&amp;gt;xl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;xh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición X.&lt;br /&gt;
* &amp;lt;code&amp;gt;yl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;yh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose con los gráficos indicados por &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMySprite_Frame0&lt;br /&gt;
    %Draw(0, 1, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. El ID debe corresponder a los gráficos dinámicos disponibles.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpriteDraw ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; comparte el contrato y las scratch de [[#Draw|Draw]], con &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;. 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 &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;. Al terminar deja los tres registros en 8 bits e incluye &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpriteDraw(offset, type)&amp;lt;/code&amp;gt; dibuja una pose dinámica utilizando las tablas de Dynamic Xtreme del tipo de sprite seleccionado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 sin desplazamiento adicional; 1 utiliza los offsets de &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A de 16 bits: ID de dibujo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt;: propiedades y prioridad.&lt;br /&gt;
* Las tablas de paleta, último volteo e índice hash de Dynamic Xtreme del tipo seleccionado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;%Draw()&amp;lt;/code&amp;gt;, utilizando las tablas estándar. Es la macro que utilizan las rutinas PIXI &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para sprites normales, las rutinas PIXI preparan los aliases de coordenadas &amp;lt;code&amp;gt;!NormalXLow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!NormalXHigh&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!NormalYLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!NormalYHigh&amp;lt;/code&amp;gt;. Si se expande la macro directamente, también deben estar definidos, como en este ejemplo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!NormalXLow = !SpriteXLow&lt;br /&gt;
!NormalXHigh = !SpriteXHigh&lt;br /&gt;
!NormalYLow = !SpriteYLow&lt;br /&gt;
!NormalYHigh = !SpriteYHigh&lt;br /&gt;
&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMySprite_Frame0&lt;br /&gt;
    %StandardSpriteDraw(0, &amp;quot;Normal&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== DrawStatic ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$45-$4F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;; con &amp;lt;code&amp;gt;offset = 1&amp;lt;/code&amp;gt;, también &amp;lt;code&amp;gt;$8B-$8C&amp;lt;/code&amp;gt;. El parámetro &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt; no recupera X desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; en esta macro. Conserva DBR y D. Incluye &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt; dibuja una pose estática, declarada con &amp;lt;code&amp;gt;.IsStatic&amp;lt;/code&amp;gt; en el DrawInfo. Sus gráficos deben estar previamente cargados en las posiciones de VRAM indicadas por sus tiles.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%DrawStatic(offset, sprite, lastFlip, palette, xl, xh, yl, yh)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 sin desplazamiento adicional; 1 utiliza &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;), con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: parámetro conservado en la firma; la implementación actual de esta macro no lo utiliza.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variable o valor que indica el volteo; &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; dibuja sin volteo.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de paleta: &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; selecciona la 8, &amp;lt;code&amp;gt;#$02&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;#$0E&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* &amp;lt;code&amp;gt;xl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;xh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición X.&lt;br /&gt;
* &amp;lt;code&amp;gt;yl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;yh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas adicionales&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID de dibujo estático.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;): propiedades y prioridad.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;): 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose sin consultar la caché de gráficos dinámicos. No requiere &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; ni una llamada previa a &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$80&lt;br /&gt;
    STA !Tile&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMyStaticSprite_Frame0&lt;br /&gt;
    %DrawStatic(0, 1, #$00, #$04, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza el tile &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; si la pose está configurada para tomarlo desde &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, sin volteo y con la paleta A. &amp;lt;code&amp;gt;!PoseIDMyStaticSprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_static_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyStaticSprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Paletas ===&lt;br /&gt;
&lt;br /&gt;
Estas macros permiten elegir qué paleta usa un sprite, cargar sus colores y cambiarlos durante el juego.&lt;br /&gt;
&lt;br /&gt;
==== LoadPaletteIDAndAddress ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; y lee &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt;. Conserva DBR y D; carry no es un indicador de éxito. La expansión continúa en la instrucción siguiente.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%LoadPaletteIDAndAddress()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 8 bits: índice de la paleta dentro del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt;: guarda aquí el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; de tu DynamicInfo, con 16 bits, como muestra el ejemplo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: ID de la paleta.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de sus colores en ROM, en formato BGR555.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    STA $0E&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    LDA #$01            ; Segunda paleta del DynamicInfo&lt;br /&gt;
    %LoadPaletteIDAndAddress()&lt;br /&gt;
    ; $00-$01 contiene su ID y $02-$04 su dirección ROM.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En PIXI también puede llamarse mediante &amp;lt;code&amp;gt;%DXLoadPaletteIDAndAddress()&amp;lt;/code&amp;gt;, con las mismas entradas y resultados. Esta variante llama a una rutina compartida y después continúa con el código siguiente.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones bajos y guiones, y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignment (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; entra con X/Y de 8 bits y A de 16 bits cuando &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; cuando se utiliza internamente; con &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, no se conserva X. Al volver, los tres quedan en 8 bits. Puede sobrescribir &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$D5&amp;lt;/code&amp;gt; y los temporales de efectos cuando corresponda. Conserva DBR y D. La macro termina con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt; asigna y carga una paleta igual que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
Si la paleta ya estaba asignada, mantiene su temporizador de uso en 2 para que no sea reemplazada mientras se utiliza. Si el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; de las opciones está activado, también aplica el efecto global correspondiente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteAssignment(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 utiliza &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; para acceder a las tablas del sprite; 0 permite usar variables independientes del índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable que recibe la paleta asignada. Debe comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Los valores &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, ..., &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; corresponden a las paletas 8-F.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteAssignment&amp;lt;/code&amp;gt;: variable o valor con formato &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; permite que Dynamic Xtreme elija el destino y cargue los colores; &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; utiliza el destino que tú indicas y carga los colores; &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; utiliza ese destino con los colores que ya tiene el nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor con formato &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;. E = 1 permite aplicar el efecto global; E = 0 lo excluye. En modo manual, PPP elige entre la paleta 8 (&amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt;) y la F (&amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt;). En automático, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F. Los cuatro bits bajos no se usan para estas opciones.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteVersion&amp;lt;/code&amp;gt;: 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 &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt;: variable que guarda la última versión procesada. Debe comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualIDGroup&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt;: juntos forman el número con el que el sistema reconoce la paleta en los modos manuales. El primero indica el grupo: &amp;lt;code&amp;gt;#$FE&amp;lt;/code&amp;gt; para normal, &amp;lt;code&amp;gt;#$FC&amp;lt;/code&amp;gt; para cluster y &amp;lt;code&amp;gt;#$FD&amp;lt;/code&amp;gt; para extended. El segundo indica el tipo de sprite; en uno normal se utiliza &amp;lt;code&amp;gt;!CustomSpriteNumber,x&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
&lt;br /&gt;
También puedes crear grupos propios: por ejemplo, usar &amp;lt;code&amp;gt;manualIDGroup = #$FB&amp;lt;/code&amp;gt; para el jugador y &amp;lt;code&amp;gt;#$FA&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt; para distinguir los recursos dentro de cada uno. Los grupos &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$FD&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FC&amp;lt;/code&amp;gt; ya son utilizados por las rutinas de sprites normales, extended y cluster, respectivamente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada adicional&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* Si &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; debe contener el índice del sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: hay una paleta con la que se puede dibujar; desactivado si todavía no hay ninguna.&lt;br /&gt;
* Guarda el número de paleta en &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt; y actualiza &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt; cuando procesa la versión.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %PaletteAssignment(1, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!NormalPaletteAssignment,x&amp;quot;, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalVersion,x&amp;quot;, &amp;quot;!NormalLastVersion,x&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las variables de un sprite normal. &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; que termina la rutina, por lo que no debes añadir código después de ella.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignmentNoUpload (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; comparte el contrato de [[#PaletteAssignment (macro general)|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 &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; solo son válidas si se leyó una paleta del DynamicInfo. Termina con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; elige una paleta como &amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt;, pero deja pendiente la carga de sus colores. Permite aplicar después un efecto local y combinarlo con el global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteAssignmentNoUpload(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los parámetros son los mismos que en &amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt;. A recibe el offset de la tabla con 16 bits. &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt; deben comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;paletteVersion&amp;lt;/code&amp;gt; elige los colores de la lista del DynamicInfo: 0 para la primera paleta, 1 para la segunda, etc. &amp;lt;code&amp;gt;paletteAssignment&amp;lt;/code&amp;gt; decide el modo: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; automático, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; manual y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; manual sin cargar colores. &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: E permite el efecto global y PPP selecciona la paleta 8-F en manual. En automático, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F. Para aplicar después un efecto local sobre los colores del DynamicInfo, utiliza el modo automático o manual con carga.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: hay una paleta asignada; desactivado si no pudo obtenerse.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: número de la paleta asignada, de dos en dos entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt;: última versión procesada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: ID de la paleta seleccionada del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de sus colores.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
Usa los datos de &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
AssignPaletteForEffect:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %PaletteAssignmentNoUpload(1, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!NormalPaletteAssignment,x&amp;quot;, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalVersion,x&amp;quot;, &amp;quot;!NormalLastVersion,x&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Después de llamar a &amp;lt;code&amp;gt;AssignPaletteForEffect&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;, comprueba el carry y aplica el efecto usando los datos devueltos. Conserva Y y &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; para la llamada de concatenación.&lt;br /&gt;
&lt;br /&gt;
La macro ya termina la rutina con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. El código que aplica el efecto va después de la llamada &amp;lt;code&amp;gt;JSL AssignPaletteForEffect&amp;lt;/code&amp;gt;, no después de la macro dentro de esa rutina.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpritePaletteAssignment ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; comparte el contrato de [[#PaletteAssignment (macro general)|PaletteAssignment (macro general)]], con &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;. Entra con X preparado para leer las tablas del sprite y con &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; correspondiente al mismo sprite. Recupera X desde ese índice cuando lo utiliza internamente; A e Y pueden cambiar. Incluye &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpritePaletteAssignment()&amp;lt;/code&amp;gt; utiliza las variables de paleta del tipo de sprite indicado. Es la macro utilizada por las rutinas PIXI de asignación.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%StandardSpritePaletteAssignment(type, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualIDGroup&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;#$FE&amp;lt;/code&amp;gt; para normal, &amp;lt;code&amp;gt;#$FC&amp;lt;/code&amp;gt; para cluster o &amp;lt;code&amp;gt;#$FD&amp;lt;/code&amp;gt; para extended.&lt;br /&gt;
* También puedes elegir un grupo propio, por ejemplo &amp;lt;code&amp;gt;#$FB&amp;lt;/code&amp;gt; para el jugador o &amp;lt;code&amp;gt;#$FA&amp;lt;/code&amp;gt; para otro tipo de entidad, siempre que esos valores no estén siendo utilizados por otro grupo de tu proyecto.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt;: variable o valor que identifica el tipo de sprite en los modos manuales.&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* Las variables de Dynamic Xtreme para paleta, opciones, versión y última versión del tipo seleccionado, preparadas como en &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;: guarda la paleta asignada en la tabla del sprite y devuelve el carry activado cuando se puede dibujar con ella.&lt;br /&gt;
&lt;br /&gt;
La macro ya incluye un &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt; y no añadas código después de la macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %StandardSpritePaletteAssignment(&amp;quot;Normal&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt; al eliminar los separadores.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpritePaletteAssignmentNoUpload ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; comparte el contrato de [[#PaletteAssignmentNoUpload (macro general)|PaletteAssignmentNoUpload (macro general)]], con &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;. X y &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; deben identificar al mismo sprite al entrar. Conserva Y y &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; de su resultado si vas a concatenar un efecto. Incluye &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpritePaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; utiliza las variables del tipo de sprite seleccionado para asignar la paleta, dejando pendiente la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%StandardSpritePaletteAssignmentNoUpload(type, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Recibe los mismos parámetros y datos que &amp;lt;code&amp;gt;%StandardSpritePaletteAssignment()&amp;lt;/code&amp;gt;. A debe contener el offset de la tabla de paletas con 16 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;: guarda la paleta asignada y devuelve el carry, Y, el ID en &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; y la dirección en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;, con las condiciones indicadas en esa entrada.&lt;br /&gt;
&lt;br /&gt;
La macro ya incluye un &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL AssignPaletteForEffect&amp;lt;/code&amp;gt;. El código que aplica el efecto va después de esa llamada.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
AssignPaletteForEffect:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %StandardSpritePaletteAssignmentNoUpload(&amp;quot;Normal&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== ReplacePalette (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; entra con A, X e Y de 8 bits y con el puntero de origen preparado en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;. A e Y pueden cambiar; con &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; con &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, no se conserva X. Los tres quedan en 8 bits. Puede sobrescribir &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; y los temporales de efectos cuando corresponda. Conserva DBR y D. Termina con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ReplacePalette()&amp;lt;/code&amp;gt; sustituye los colores de una paleta que ya estás usando. Hace lo mismo que &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, pero tú eliges qué variables leer. Si otros sprites o códigos usan esa misma paleta, también verán los nuevos colores.&lt;br /&gt;
&lt;br /&gt;
Suele utilizarse después de una asignación sin carga, como &amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;. Primero obtienes la paleta asignada y después preparas en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; la dirección de los colores que quieres usar para reemplazarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%ReplacePalette(sprite, paletteOption, palette)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 obtiene el índice del sprite desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 0 utiliza variables independientes de ese índice.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor de las opciones de paleta. El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica si se aplica el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de la paleta de destino, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de los nuevos colores en BGR555.&lt;br /&gt;
* A en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Llámala cuando cambien los colores que quieres mostrar. Repetir la llamada cada frame obliga a preparar de nuevo la paleta y sus efectos.&lt;br /&gt;
&lt;br /&gt;
Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL ReplaceSpritePalette&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
ReplaceSpritePalette:&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;8&lt;br /&gt;
    STA $03&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
    %ReplacePalette(1, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyAlternatePalette&amp;lt;/code&amp;gt; es la dirección de una paleta insertada a partir de los recursos del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_alternate_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyAlternatePalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Cargar colores con TransferPalette ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros comunes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;: primer color que se cambiará, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Es un operando de 8 bits: &amp;lt;code&amp;gt;#$91&amp;lt;/code&amp;gt; empieza en el color 1 de la paleta 9; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; utiliza el número guardado en esa scratch.&lt;br /&gt;
* &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt;: cantidad de bytes que se copiarán. Es un valor conocido al ensamblar, &#039;&#039;&#039;sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;&#039;&#039;&#039;: &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; copia 15 colores. Debe ser mayor que cero y par, y la carga no debe pasar del último color de CGRAM.&lt;br /&gt;
* &amp;lt;code&amp;gt;GlobalEffect&amp;lt;/code&amp;gt;: utiliza &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; para cargar sin efecto global o &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; para que la paleta reciba el efecto global. Es una opción fija de la llamada, no una variable de RAM.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué hace GlobalEffect&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Comportamiento&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;GlobalEffect = 1&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas y resultado comunes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Entra con A, X e Y en modo de 8 bits. D debe ser &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; en LoROM o &amp;lt;code&amp;gt;$3000&amp;lt;/code&amp;gt; en el contexto habitual de SA-1 Pack. DBR debe permitir acceder al buffer de paletas de SMW: &amp;lt;code&amp;gt;$0703&amp;lt;/code&amp;gt; en LoROM o su espejo &amp;lt;code&amp;gt;$6703&amp;lt;/code&amp;gt; en SA-1. Los bancos habituales con espejos de RAM, como &amp;lt;code&amp;gt;$00-$3F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$80-$BF&amp;lt;/code&amp;gt;, permiten esos accesos. Si pasas tablas con direcciones de 16 bits, DBR también debe permitir leerlas.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* Las llamadas pueden modificar &amp;lt;code&amp;gt;$68-$6D&amp;lt;/code&amp;gt; cuando están habilitados los efectos; las variantes &amp;lt;code&amp;gt;FromAddress&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FromTable&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt;, incluida &amp;lt;code&amp;gt;ResourceWithLength&amp;lt;/code&amp;gt;, también utilizan &amp;lt;code&amp;gt;$65-$67&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
* No incluyen &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;: el código continúa después de la macro.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteFromAddress ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteFromAddress()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteFromAddress(Address, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Address&amp;lt;/code&amp;gt;: dirección de origen completa, sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Paleta 9, colores 1-F, con efecto global.&lt;br /&gt;
    %TransferPaletteFromAddress(!PaletteMyPalette, #$91, $001E, 1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; se genera al instalar una paleta declarada en &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; de un DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase: se eliminan espacios, guiones bajos y guiones, y se pone en mayúscula la inicial de cada palabra. Por ejemplo, &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteFromPointer ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteFromPointer()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteFromPointer(Pointer, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Pointer&amp;lt;/code&amp;gt;: dirección del primer byte de la scratch, sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;. Los tres bytes deben contener la dirección de origen en orden bajo, alto y banco. Por ejemplo, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Preparar la dirección de la paleta en $02-$04.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!PaletteMyPalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.b #!PaletteMyPalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
&lt;br /&gt;
    ; Paleta 9, colores 1-F, sin efecto global.&lt;br /&gt;
    %TransferPaletteFromPointer($02, #$91, $001E, 0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; se genera desde una paleta del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteFromTable ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteFromTable()&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;$65-$67&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteFromTable(TableAddr, TableBNK, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;TableAddr&amp;lt;/code&amp;gt;: operando que se lee con A de 16 bits para obtener los dos bytes de dirección.&lt;br /&gt;
* &amp;lt;code&amp;gt;TableBNK&amp;lt;/code&amp;gt;: operando que se lee con A de 8 bits para obtener el banco.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; $02-$03 contiene la dirección y $04 contiene el banco.&lt;br /&gt;
    %TransferPaletteFromTable(&amp;quot;$02&amp;quot;, &amp;quot;$04&amp;quot;, #$91, $001E, 1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A diferencia de &amp;lt;code&amp;gt;FromPointer&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteResource ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteResource()&amp;lt;/code&amp;gt; carga una paleta registrada en el DynamicInfo utilizando su tamaño completo. No necesitas escribir su dirección ni su cantidad de bytes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferPaletteResource(Name, CGRAMOffset, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Name&amp;lt;/code&amp;gt;: nombre normalizado de la paleta, sin prefijo &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt; y sin extensión. La macro utiliza &amp;lt;code&amp;gt;!Palette&amp;amp;lt;Name&amp;amp;gt;&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Palette&amp;amp;lt;Name&amp;amp;gt;Size&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; MyPalette contiene 15 colores.&lt;br /&gt;
    %TransferPaletteResource(MyPalette, #$91, 1)&lt;br /&gt;
    BCS .Accepted&lt;br /&gt;
    ; No se aceptó la carga directa: volver a intentarlo después.&lt;br /&gt;
    RTL&lt;br /&gt;
.Accepted&lt;br /&gt;
    ; Continuar con el resto del código.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo continúa en &amp;lt;code&amp;gt;.Accepted&amp;lt;/code&amp;gt; si se aceptó la carga directa o se prepararon los colores para el efecto global. El &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; pertenece al ejemplo, no a la macro.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; corresponde a los defines &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteMyPaletteSize&amp;lt;/code&amp;gt;, generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; desde la sección &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; del DynamicInfo. El nombre usa PascalCase eliminando espacios, guiones bajos y guiones: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;. Esta llamada no utiliza los defines &amp;lt;code&amp;gt;!Resource...&amp;lt;/code&amp;gt; de la sección &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; ni las paletas convertidas RGB/HSL de un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteResourceWithLength ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteResourceWithLength()&amp;lt;/code&amp;gt; utiliza la dirección de una paleta registrada, pero permite copiar solo la cantidad de bytes que indiques.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteResourceWithLength(Name, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Name&amp;lt;/code&amp;gt;: nombre normalizado de la paleta, igual que en &amp;lt;code&amp;gt;%TransferPaletteResource()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt;: cantidad de bytes que se copiarán, sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;. No debe superar el tamaño del recurso.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Copiar 4 colores al comienzo de la paleta 9, sin efecto global.&lt;br /&gt;
    %TransferPaletteResourceWithLength(MyPalette, #$90, $0008, 0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; utiliza el define &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt;, generado desde una paleta del DynamicInfo y publicado en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TransferPaletteCommon&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TransferPaletteData&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Efectos de paleta ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 [[es/Dynamic_Xtreme_files_and_formats#Tipos_de_efectos|Tipos de efectos]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;¿Qué llamada necesitas?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Quieres… !! Utiliza…&lt;br /&gt;
|-&lt;br /&gt;
| Teñir una paleta o cambiar su tono, saturación o luminosidad. || &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MixAndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Pasar de una paleta a otra. || &amp;lt;code&amp;gt;PaletteTransition&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Aplicar un efecto que ya definiste en un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. || &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DoEffectAndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Darle un efecto propio a un sprite y conservar además el efecto global. || &amp;lt;code&amp;gt;ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; o su variante HSL, después de asignar la paleta sin carga.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para calcular un efecto directamente, el proceso habitual es preparar los colores originales con &amp;lt;code&amp;gt;SetRGBBase&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;SetHSLBase&amp;lt;/code&amp;gt; y después aplicar el cambio. Los ejemplos utilizan las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt;, que trabajan con las copias de paleta de Dynamic Xtreme y evitan escribir direcciones de memoria.&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, estas ya se encargan de preparar los colores y completar su carga.&lt;br /&gt;
&lt;br /&gt;
En los ejemplos, prepara A en modo de 8 bits antes de llamar a las macros.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal de los efectos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Las macros de preparación de bases, mezcla, transición, conversión y &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; entran con A, X e Y de 8 bits. Sus variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; utilizan el mismo contrato. Las macros de concatenación tienen una entrada diferente, descrita en su apartado.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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 y memoria temporal|estado del CPU]].&lt;br /&gt;
* Pueden sobrescribir &amp;lt;code&amp;gt;$00-$0F&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$45-$54&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8A-$8F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$D5-$D7&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; se lee con A de 16 bits. Prepara los operandos de memoria con el tamaño correspondiente.&lt;br /&gt;
* 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.&lt;br /&gt;
&lt;br /&gt;
==== Preparar los colores: SetRGBBase y SetHSLBase ====&lt;br /&gt;
&lt;br /&gt;
Antes de modificar los colores, necesitas una copia con la que calcular el efecto. &amp;lt;code&amp;gt;%SetRGBBase()&amp;lt;/code&amp;gt; prepara esa copia para efectos RGB; &amp;lt;code&amp;gt;%SetHSLBase()&amp;lt;/code&amp;gt; la prepara para HSL. Si los colores originales no cambiaron, puedes reutilizarla en los siguientes frames.&lt;br /&gt;
&lt;br /&gt;
En las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; solo indicas el primer color y cuántos colores quieres preparar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%SetRGBBaseDefault(offset, length)&lt;br /&gt;
%SetHSLBaseDefault(offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; es el número del primer color y &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; es la cantidad. Por ejemplo, &amp;lt;code&amp;gt;#$0081&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;#$000F&amp;lt;/code&amp;gt; seleccionan los 15 colores visibles de la paleta 8.&lt;br /&gt;
&lt;br /&gt;
Si necesitas elegir tú las direcciones donde leer y guardar los colores, utiliza las versiones completas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%SetRGBBase(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%SetHSLBase(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;%SetRGBBaseDefault(offset, length)&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%SetHSLBaseDefault(offset, length)&amp;lt;/code&amp;gt; leen de &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; y guardan el resultado en &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: preparar una paleta de sprites&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Paleta 8, sin incluir su primer color transparente.&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
    ; Para trabajar en HSL, utiliza esta variante en su lugar:&lt;br /&gt;
    ; %SetHSLBaseDefault(#$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$81&amp;lt;/code&amp;gt; es el segundo color de la paleta 8: la paleta comienza en el color &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; y se procesan los 15 siguientes.&lt;br /&gt;
&lt;br /&gt;
==== Mezclar colores: Mix y MixAndMerge ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Los parámetros &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; indican el color que quieres alcanzar, entre 0 y 31. Los parámetros &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#$7F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para RGB, los valores 1, 2 y 3 corresponden a rojo, verde y azul. Para HSL corresponden a tono, saturación y luminosidad.&lt;br /&gt;
&lt;br /&gt;
El final del nombre indica qué componentes se modifican:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! RGB !! HSL !! Componentes modificados&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;H&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;L&amp;lt;/code&amp;gt; || Uno.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GB&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SL&amp;lt;/code&amp;gt; || Dos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RGB&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HSL&amp;lt;/code&amp;gt; || Los tres.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada combinación está disponible como &amp;lt;code&amp;gt;Mix...&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixAndMerge...&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;MixAndMerge...Default&amp;lt;/code&amp;gt;. Por ejemplo: &amp;lt;code&amp;gt;%MixR()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%MixAndMergeR()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%MixAndMergeRDefault()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; omiten las direcciones.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%MixRGB(r1, r2, r3, v1, v2, v3, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%MixAndMergeRG(r1, r2, v1, v2, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%MixAndMergeLDefault(r3, v3, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo RGB: teñir de rojo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; Preparar los colores originales de la paleta 8.&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
    ; Acercar los tres componentes a un rojo puro, aproximadamente a la mitad.&lt;br /&gt;
    %MixAndMergeRGBDefault(#$40, #$40, #$40, #$1F, #$00, #$00, #$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los tres primeros valores &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt; indican la intensidad del cambio para rojo, verde y azul. Los siguientes, &amp;lt;code&amp;gt;#$1F, #$00, #$00&amp;lt;/code&amp;gt;, indican el rojo puro al que se acercarán. Los dos últimos seleccionan los 15 colores de la paleta 8.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo HSL: aclarar la paleta&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %SetHSLBaseDefault(#$0081, #$000F)&lt;br /&gt;
    %MixAndMergeLDefault(#$40, #$1F, #$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aquí solo cambia la luminosidad: &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt; aplica aproximadamente la mitad del cambio y &amp;lt;code&amp;gt;#$1F&amp;lt;/code&amp;gt; indica la luminosidad máxima. Este es un ejemplo independiente del anterior.&lt;br /&gt;
&lt;br /&gt;
==== Cambiar entre paletas: PaletteTransition ====&lt;br /&gt;
&lt;br /&gt;
Estas macros acercan cada color de la paleta original al color correspondiente de otra paleta. A diferencia de &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt;, cada color tiene su propio destino. Sirven, por ejemplo, para pasar de los colores normales de un sprite a una paleta de daño.&lt;br /&gt;
&lt;br /&gt;
Las variantes son &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransitionHSL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransitionRGBAndMerge&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PaletteTransitionHSLAndMerge&amp;lt;/code&amp;gt;. Las dos variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; también tienen versión &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteTransitionRGB(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%PaletteTransitionHSLAndMerge(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%PaletteTransitionRGBAndMergeDefault(r1, r2, r3, targetpal, targetpalbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;targetpal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;targetpalbnk&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: calcular un paso intermedio de una transición&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; Este ejemplo trabaja con los primeros 15 colores de la copia de paletas.&lt;br /&gt;
    %SetRGBBaseDefault(#$0000, #$000F)&lt;br /&gt;
    %PaletteTransitionRGBAndMergeDefault(#$40, #$40, #$40, #!PaletteMyTargetRGB, #!PaletteMyTargetRGB&amp;gt;&amp;gt;16, #$0000, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo supone que &amp;lt;code&amp;gt;!PaletteMyTargetRGB&amp;lt;/code&amp;gt; corresponde a una paleta de destino RGB generada al instalar un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; de transición. Su dirección queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_target&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyTarget&amp;lt;/code&amp;gt;. Para HSL se utiliza la paleta convertida a HSL y la macro correspondiente.&lt;br /&gt;
&lt;br /&gt;
==== Aplicar un efecto de un archivo: DoEffect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DoEffect()&amp;lt;/code&amp;gt; aplica un efecto de un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%DoEffect(effect, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%DoEffectAndMerge(effect, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%DoEffectAndMergeDefaultRGB(effect, offset, length)&lt;br /&gt;
%DoEffectAndMergeDefaultHSL(effect, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;effect&amp;lt;/code&amp;gt;: ID del efecto, como &amp;lt;code&amp;gt;#!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt;.&lt;br /&gt;
* El origen debe contener colores RGB o HSL separados, según el efecto elegido.&lt;br /&gt;
* &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; guarda el resultado con 3 bytes por color para poder seguir modificándolo.&lt;br /&gt;
* &amp;lt;code&amp;gt;DoEffectAndMerge&amp;lt;/code&amp;gt; guarda colores en formato de SNES. Las variantes &amp;lt;code&amp;gt;DefaultRGB&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DefaultHSL&amp;lt;/code&amp;gt; eligen la base correspondiente y escriben en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: aplicar un efecto RGB a la paleta 8&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
    %DoEffectAndMergeDefaultRGB(#!PaletteEffectIDMyEffect0, #$81, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; se genera desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. El número final identifica el efecto dentro del archivo. Si el efecto trabaja en HSL, prepara la base HSL y utiliza &amp;lt;code&amp;gt;%DoEffectAndMergeDefaultHSL()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Convertir entre RGB y HSL ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%RGBToHSL()&amp;lt;/code&amp;gt; convierte colores RGB a HSL y &amp;lt;code&amp;gt;%HSLToRGB()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%RGBToHSL(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%HSLToRGB(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: convertir la base RGB a HSL&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %RGBToHSL(#DX_PPU_CGRAM_BaseRGBPalette, #DX_PPU_CGRAM_BaseRGBPalette&amp;gt;&amp;gt;16, #DX_PPU_CGRAM_BaseHSLPalette, #DX_PPU_CGRAM_BaseHSLPalette&amp;gt;&amp;gt;16, #$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Combinar un efecto propio con el global ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; 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 &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, X se recupera desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; con &amp;lt;code&amp;gt;sprite = 0&amp;lt;/code&amp;gt;, no se conserva X. A e Y pueden cambiar. Utilizan los temporales de efectos y &amp;lt;code&amp;gt;$F0-$F3&amp;lt;/code&amp;gt;. Conservan DBR y D. A diferencia de las demás macros de efectos, incluyen &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; y devuelven disponibilidad mediante carry, también cuando reutilizan un resultado anterior.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Suelen utilizarse después de &amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%ConcatenateRGBPaletteEffectToGlobal(sprite, paletteOption, palette)&lt;br /&gt;
%ConcatenateHSLPaletteEffectToGlobal(sprite, paletteOption, palette)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 recupera el índice del sprite desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 0 permite utilizar variables propias.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor de las opciones de paleta; activa el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; para incluir el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable que contiene la paleta asignada, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos.&lt;br /&gt;
* A de 16 bits: ID del efecto local RGB o HSL, según la macro.&lt;br /&gt;
* X de 8 bits: copia del valor de la paleta asignada.&lt;br /&gt;
* Y de 8 bits: conserva el valor devuelto por la asignación sin carga.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de los colores originales preparada por esa asignación.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: completar una asignación sin carga&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
; Llamar esta rutina con JSL después de asignar la paleta sin carga.&lt;br /&gt;
; Deben conservarse Y y $02-$04 de aquella llamada.&lt;br /&gt;
ApplyLocalEffect:&lt;br /&gt;
    LDA !NormalPalette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyEffect0&lt;br /&gt;
    %ConcatenateRGBPaletteEffectToGlobal(1, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; se genera desde un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. Para un efecto HSL, utiliza la macro HSL. Si usas Y para leer una tabla de efectos, guarda su valor con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; y recupéralo con &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; antes de concatenar.&lt;br /&gt;
&lt;br /&gt;
==== Elegir las direcciones y combinar varios efectos ====&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; 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:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;src&amp;lt;/code&amp;gt;: dónde leer los colores originales; &amp;lt;code&amp;gt;srcbnk&amp;lt;/code&amp;gt;: su banco.&lt;br /&gt;
* &amp;lt;code&amp;gt;dst&amp;lt;/code&amp;gt;: dónde guardar el resultado; &amp;lt;code&amp;gt;dstbnk&amp;lt;/code&amp;gt;: su banco. El destino debe ser un espacio de RAM que tu código pueda utilizar.&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: primer color que se procesará, contando desde 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt;: cantidad de colores que se procesarán.&lt;br /&gt;
&lt;br /&gt;
Para indicar una dirección fija, se utiliza &amp;lt;code&amp;gt;#Nombre&amp;lt;/code&amp;gt; para la dirección y &amp;lt;code&amp;gt;#Nombre&amp;gt;&amp;gt;16&amp;lt;/code&amp;gt; para su banco, como en el ejemplo de conversión RGB a HSL. También puedes pasar variables que contengan esos datos.&lt;br /&gt;
&lt;br /&gt;
El espacio necesario depende del paso que estés realizando:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Operación !! Lee !! Guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SetRGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SetHSLBase&amp;lt;/code&amp;gt; || Paleta normal: 2 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransition&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; sin &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| Variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Paleta normal: 2 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RGBToHSL&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;HSLToRGB&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si quieres aplicar dos efectos seguidos, el primero debe guardar sus colores separados, sin &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt;. El segundo lee ese resultado y utiliza &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; para dejar la paleta lista para cargarla. Si uno trabaja en RGB y el otro en HSL, convierte los colores entre ambos pasos.&lt;br /&gt;
&lt;br /&gt;
Las macros utilizan memoria temporal, entre otras las direcciones &amp;lt;code&amp;gt;$45-$50&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$51-$53&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8C&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8E&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$D5-$D7&amp;lt;/code&amp;gt;, según la operación. No guardes en ellas datos que necesites conservar después de la llamada.&lt;br /&gt;
&lt;br /&gt;
=== PPU ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué llamada elegir&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Necesitas… !! VRAM !! CGRAM&lt;br /&gt;
|-&lt;br /&gt;
| Indicar la dirección de origen y su banco por separado. || &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Indicar una dirección completa y dejar que la macro obtenga el banco. || &amp;lt;code&amp;gt;TransferToVRAMFromAddr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferToCGRAMFromAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Cargar un recurso completo registrado en Dynamic Xtreme. || &amp;lt;code&amp;gt;TransferResourceToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferResourceToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Cargar solo una cantidad de bytes de un recurso. || &amp;lt;code&amp;gt;TransferResourceToVRAMWithLenght&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferResourceToCGRAMWithLenght&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las versiones normales comprueban si la transferencia cabe dentro del límite de bytes del frame:&lt;br /&gt;
&lt;br /&gt;
* Carry activado: la transferencia quedó programada.&lt;br /&gt;
* Carry desactivado: no se programó porque superaría ese límite. Tu código puede intentarlo en otro frame.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal de las transferencias&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;, especialmente las de CGRAM.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* No incluyen &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. 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 &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; no devuelven un indicador de éxito en carry.&lt;br /&gt;
&lt;br /&gt;
Estas reglas también se aplican a las variantes &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;WithLenght&amp;lt;/code&amp;gt;: preparan los argumentos y expanden la misma transferencia.&lt;br /&gt;
&lt;br /&gt;
==== TransferToVRAM ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; programa una copia de gráficos desde ROM o RAM hacia VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToVRAM(VRAMOffset, ResourceAddr, ResourceBNK, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;VRAMOffset&amp;lt;/code&amp;gt;: dirección de destino en VRAM, expresada en palabras de 2 bytes. Por ejemplo, copiar &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes desde &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; ocupa las palabras &amp;lt;code&amp;gt;$6000-$60FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;ResourceAddr&amp;lt;/code&amp;gt;: dirección de origen dentro de su banco.&lt;br /&gt;
* &amp;lt;code&amp;gt;ResourceBNK&amp;lt;/code&amp;gt;: banco del origen.&lt;br /&gt;
* &amp;lt;code&amp;gt;Lenght&amp;lt;/code&amp;gt;: cantidad de bytes que se copiarán. Se conserva esta escritura del nombre porque así aparece en la macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: programar la carga de gráficos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToVRAM(#$6000, #!ResourceMyGraphics, #!ResourceMyGraphics&amp;gt;&amp;gt;16, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
    ; La copia se realizará en el próximo NMI.&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; es la dirección de un recurso registrado desde un DynamicInfo; queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;. La cantidad de bytes solicitada debe existir en ese recurso.&lt;br /&gt;
&lt;br /&gt;
==== TransferToVRAMFromAddr ====&lt;br /&gt;
&lt;br /&gt;
Hace la misma copia, pero recibe la dirección completa del origen. La macro separa su dirección y banco por ti.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToVRAMFromAddr(VRAMOffset, addr, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; se escribe sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;; los otros parámetros se entregan como en &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferToVRAMFromAddr(#$6000, !ResourceMyGraphics, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; se genera desde un recurso del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferResourceToVRAM y TransferResourceToVRAMWithLenght ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferResourceToVRAM(VRAMOffset, ResourceName)&lt;br /&gt;
%TransferResourceToVRAMWithLenght(VRAMOffset, ResourceName, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para un recurso cuyos defines sean &amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceMyGraphicsSize&amp;lt;/code&amp;gt;, escribe &amp;lt;code&amp;gt;&amp;quot;MyGraphics&amp;quot;&amp;lt;/code&amp;gt; como &amp;lt;code&amp;gt;ResourceName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: cargar el recurso completo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToVRAM(#$6000, &amp;quot;MyGraphics&amp;quot;)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: cargar solo sus primeros $0200 bytes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToVRAMWithLenght(#$6000, &amp;quot;MyGraphics&amp;quot;, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El nombre y el tamaño se obtienen de los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; al instalar los recursos del DynamicInfo. Utiliza el nombre normalizado: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;, eliminando los separadores y poniendo en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
==== TransferToCGRAM ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt; programa una copia de colores desde ROM o RAM hacia una paleta de SNES.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToCGRAM(CGRAMOffset, TableAddr, TableBNK, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;: número del primer color de destino, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Por ejemplo, la paleta 8 comienza en el color &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;TableAddr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TableBNK&amp;lt;/code&amp;gt;: dirección y banco de los colores que se van a copiar.&lt;br /&gt;
* &amp;lt;code&amp;gt;Lenght&amp;lt;/code&amp;gt;: cantidad de bytes. Cada color ocupa 2 bytes; 15 colores ocupan &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar los 15 colores visibles de la paleta 8&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToCGRAM(#$81, #DX_PPU_CGRAM_PaletteWriteMirror+$0102, #DX_PPU_CGRAM_PaletteWriteMirror&amp;gt;&amp;gt;16, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Este ejemplo toma el resultado de un efecto guardado en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;. El desplazamiento &amp;lt;code&amp;gt;$0102&amp;lt;/code&amp;gt; corresponde al color &amp;lt;code&amp;gt;$81&amp;lt;/code&amp;gt;, porque cada color ocupa 2 bytes. Se omite el primer color de la paleta, que es transparente en sprites.&lt;br /&gt;
&lt;br /&gt;
==== TransferToCGRAMFromAddr ====&lt;br /&gt;
&lt;br /&gt;
Hace la misma copia de colores, pero recibe la dirección completa del origen. Escribe &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToCGRAMFromAddr(CGRAMOffset, addr, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToCGRAMFromAddr(#$81, DX_PPU_CGRAM_PaletteWriteMirror+$0102, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== TransferResourceToCGRAM y TransferResourceToCGRAMWithLenght ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferResourceToCGRAM(CGRAMOffset, ResourceName)&lt;br /&gt;
%TransferResourceToCGRAMWithLenght(CGRAMOffset, ResourceName, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar un recurso completo de colores&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToCGRAM(#$80, &amp;quot;MyColors&amp;quot;)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar solo 15 colores&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToCGRAMWithLenght(#$81, &amp;quot;MyColors&amp;quot;, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Estos ejemplos suponen un recurso general de colores con los defines &amp;lt;code&amp;gt;!ResourceMyColors&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceMyColorsSize&amp;lt;/code&amp;gt;, generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; desde un DynamicInfo. Utiliza el nombre normalizado: &amp;lt;code&amp;gt;my_colors&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyColors&amp;lt;/code&amp;gt;. En el segundo ejemplo, el recurso debe comenzar con los 15 colores que se quieren copiar, sin anteponer el color transparente.&lt;br /&gt;
&lt;br /&gt;
==== Variantes Forced ====&lt;br /&gt;
&lt;br /&gt;
Todas las transferencias anteriores tienen una variante cuyo nombre comienza con &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;. Programa la copia aunque supere el límite de bytes del frame. La cantidad copiada también se suma al total de ese frame.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! VRAM !! CGRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferToVRAMFromAddr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferToCGRAMFromAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferResourceToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferResourceToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferResourceToVRAMWithLenght&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferResourceToCGRAMWithLenght&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Reciben los mismos parámetros que las versiones sin &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %ForcedTransferResourceToVRAM(#$6000, &amp;quot;MyGraphics&amp;quot;)&lt;br /&gt;
    ; No se comprueba el carry en esta variante.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt; corresponde al recurso &amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, generado desde el DynamicInfo. Se utiliza el nombre normalizado, como &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Matemáticas ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Prepara A en modo de 8 bits antes de llamarlas. Las macros no cambian por ti el tamaño de A, X o Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Registros y memoria temporal:&#039;&#039;&#039; todas las macros de esta categoría, incluidas &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;After...&amp;lt;/code&amp;gt;, 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 &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cómo escribir los argumentos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Mul&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Div&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MulAfterMul&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DivAfterDiv&amp;lt;/code&amp;gt; pegan el argumento directamente después de &amp;lt;code&amp;gt;LDA&amp;lt;/code&amp;gt;. Escribe el argumento entre comillas con un espacio al principio: &amp;lt;code&amp;gt;&amp;quot; #$05&amp;quot;&amp;lt;/code&amp;gt; produce &amp;lt;code&amp;gt;LDA #$05&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También puedes comenzar el argumento con &amp;lt;code&amp;gt;.b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;.l&amp;lt;/code&amp;gt; para elegir cómo se escribe el acceso a memoria. Por ejemplo, si &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; contiene el número que quieres multiplicar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot;.b $02&amp;quot;, &amp;quot; #$07&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esto genera &amp;lt;code&amp;gt;LDA.b $02&amp;lt;/code&amp;gt; para leer el primer número y &amp;lt;code&amp;gt;LDA #$07&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Las variantes con &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt;, además de &amp;lt;code&amp;gt;MulAfterDiv&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DivAfterMul&amp;lt;/code&amp;gt;, ya añaden un espacio antes de los argumentos. En ellas puedes escribir los valores normalmente, como &amp;lt;code&amp;gt;%MulW(#$05, #$07)&amp;lt;/code&amp;gt;. En la implementación actual no se pasan los sufijos &amp;lt;code&amp;gt;.b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;.l&amp;lt;/code&amp;gt; de esta misma manera a esas variantes, porque el espacio que añaden quedaría entre &amp;lt;code&amp;gt;LDA&amp;lt;/code&amp;gt; y el sufijo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;¿Qué significa la W?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El hardware necesita un pequeño tiempo para terminar el cálculo. Las macros con &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; incluyen esa espera: puedes leer el resultado inmediatamente después. Las versiones sin &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los resultados se leen mediante estos defines:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!MultiplicationResult&amp;lt;/code&amp;gt;: resultado de multiplicar, de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;!DivisionResult&amp;lt;/code&amp;gt;: cociente de la división, de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;!RemainderResult&amp;lt;/code&amp;gt;: resto de la división, de 16 bits.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Mul y MulW ====&lt;br /&gt;
&lt;br /&gt;
Multiplican dos valores de 8 bits y producen un resultado de 16 bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Mul(a, b)&lt;br /&gt;
%MulW(a, b)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; pueden ser valores inmediatos, como &amp;lt;code&amp;gt;#$06&amp;lt;/code&amp;gt;, o variables de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: 6 × 7 = 42&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %MulW(#$06, #$07)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $002A, es decir, 42&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La llamada sin espera sería &amp;lt;code&amp;gt;%Mul(&amp;quot; #$06&amp;quot;, &amp;quot; #$07&amp;quot;)&amp;lt;/code&amp;gt;. En ese caso no leas el resultado inmediatamente: ejecuta antes otro código que no utilice el hardware de multiplicación o división.&lt;br /&gt;
&lt;br /&gt;
==== Div y DivW ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Div(ah, al, b)&lt;br /&gt;
%DivW(ah, al, b)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;ah&amp;lt;/code&amp;gt;: byte alto del número que quieres dividir.&lt;br /&gt;
* &amp;lt;code&amp;gt;al&amp;lt;/code&amp;gt;: byte bajo del mismo número.&lt;br /&gt;
* &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;: número por el que divides, entre 1 y 255.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: 300 ÷ 7 = 42, con resto 6&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; 300 = $012C: byte alto $01, byte bajo $2C.&lt;br /&gt;
    %DivW(#$01, #$2C, #$07)&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $002A, es decir, 42&lt;br /&gt;
    LDA !RemainderResult         ; A = $0006&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
También puedes pasar una variable de 16 bits como dos argumentos: &amp;lt;code&amp;gt;%DivW(MiNumero+1, MiNumero, #$07)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;MiNumero&amp;lt;/code&amp;gt; representa aquí una variable definida por tu código.&lt;br /&gt;
&lt;br /&gt;
==== Continuar desde el resultado anterior ====&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;AfterMul&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;AfterDiv&amp;lt;/code&amp;gt; toman el resultado del cálculo anterior como primer número. Solo debes indicar el segundo número.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Macro !! Cálculo que realiza&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MulAfterMul(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MulWAfterMul(b)&amp;lt;/code&amp;gt; || Toma los 8 bits bajos del resultado de la multiplicación anterior y los multiplica por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MulAfterDiv(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MulWAfterDiv(b)&amp;lt;/code&amp;gt; || Toma los 8 bits bajos del cociente anterior y los multiplica por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DivAfterMul(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DivWAfterMul(b)&amp;lt;/code&amp;gt; || Divide el resultado completo de la multiplicación anterior por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DivAfterDiv(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DivWAfterDiv(b)&amp;lt;/code&amp;gt; || Divide el cociente completo de la división anterior por b.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La W sigue indicando que puedes leer el nuevo resultado inmediatamente después. Las variantes &amp;lt;code&amp;gt;After...&amp;lt;/code&amp;gt; ya incluyen la espera que necesitan para tomar el resultado del cálculo anterior.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dos multiplicaciones, (6 × 7) × 2 = 84&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot; #$06&amp;quot;, &amp;quot; #$07&amp;quot;)&lt;br /&gt;
    %MulWAfterMul(#$02)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $0054, es decir, 84&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dividir y después multiplicar, (100 ÷ 4) × 3 = 75&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Div(&amp;quot; #$00&amp;quot;, &amp;quot; #$64&amp;quot;, &amp;quot; #$04&amp;quot;)&lt;br /&gt;
    %MulWAfterDiv(#$03)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $004B, es decir, 75&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: multiplicar y después dividir, (20 × 15) ÷ 4 = 75&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot; #$14&amp;quot;, &amp;quot; #$0F&amp;quot;)&lt;br /&gt;
    %DivWAfterMul(#$04)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $004B, es decir, 75&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dos divisiones, (300 ÷ 3) ÷ 4 = 25&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Div(&amp;quot; #$01&amp;quot;, &amp;quot; #$2C&amp;quot;, &amp;quot; #$03&amp;quot;)&lt;br /&gt;
    %DivWAfterDiv(#$04)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $0019, es decir, 25&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En las multiplicaciones, el primer número siempre se limita a 8 bits. Si el resultado anterior era mayor que 255, &amp;lt;code&amp;gt;MulAfterMul&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;MulAfterDiv&amp;lt;/code&amp;gt; solo utilizará su byte bajo. Las divisiones de esta tabla sí toman el resultado anterior completo, de 16 bits.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_Quick_Start&amp;diff=21383</id>
		<title>es/Dynamic Xtreme Quick Start</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_Quick_Start&amp;diff=21383"/>
		<updated>2026-10-25T17:15:30Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_Quick_Start}}&lt;br /&gt;
&lt;br /&gt;
Esta guía explica cómo realizar una instalación básica de Dynamic&lt;br /&gt;
Xtreme en Windows o Linux.&lt;br /&gt;
&lt;br /&gt;
Si es la primera vez que utilizas la herramienta, sigue los pasos en&lt;br /&gt;
el orden indicado. No es necesario conocer el funcionamiento interno&lt;br /&gt;
del sistema para completar la instalación.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme requiere el runtime de .NET 8. Descarga e instala la&lt;br /&gt;
versión correspondiente a tu sistema operativo desde el sitio oficial&lt;br /&gt;
de Microsoft:&lt;br /&gt;
&lt;br /&gt;
[https://dotnet.microsoft.com/download/dotnet/8.0 .NET 8 Runtime]&lt;br /&gt;
&lt;br /&gt;
La herramienta es compatible con Windows y Linux. Solo necesitas el&lt;br /&gt;
runtime de .NET; no es necesario instalar el SDK completo.&lt;br /&gt;
&lt;br /&gt;
Puedes descargar Dynamic Xtreme desde SNEStorage: [https://snestorage.dev/Resource/7 SNEStorage - Dynamic Xtreme]&lt;br /&gt;
&lt;br /&gt;
== Preparar los recursos ==&lt;br /&gt;
&lt;br /&gt;
Antes de ejecutar Dynamic Xtreme, añade a tu proyecto todos los&lt;br /&gt;
recursos que deseas instalar.&lt;br /&gt;
&lt;br /&gt;
=== Recursos para PIXI y UberASMTool ===&lt;br /&gt;
&lt;br /&gt;
Los recursos actuales normalmente incluyen su archivo&lt;br /&gt;
&amp;lt;code&amp;gt;*.asm&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;*.json&amp;lt;/code&amp;gt; junto con los archivos que&lt;br /&gt;
necesitan. Copia el paquete completo sin cambiar su estructura de&lt;br /&gt;
carpetas.&lt;br /&gt;
&lt;br /&gt;
En PIXI, utiliza la carpeta correspondiente al tipo de sprite:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprites&amp;lt;/code&amp;gt; para sprites normales.&lt;br /&gt;
* &amp;lt;code&amp;gt;cluster&amp;lt;/code&amp;gt; para cluster sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;extended&amp;lt;/code&amp;gt; para extended sprites.&lt;br /&gt;
* Para otros tipos, utiliza la carpeta indicada por el recurso.&lt;br /&gt;
&lt;br /&gt;
En UberASMTool, utiliza la carpeta correspondiente al tipo de código:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;level&amp;lt;/code&amp;gt; para códigos de nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;overworld&amp;lt;/code&amp;gt; para códigos del overworld.&lt;br /&gt;
* &amp;lt;code&amp;gt;gamemode&amp;lt;/code&amp;gt; para códigos de game mode.&lt;br /&gt;
* Para otros tipos, utiliza la carpeta indicada por el recurso.&lt;br /&gt;
&lt;br /&gt;
Después de copiar el recurso, añádelo al archivo de lista de PIXI o&lt;br /&gt;
UberASMTool como lo harías normalmente.&lt;br /&gt;
&lt;br /&gt;
Los recursos preparados para Dynamic Xtreme ya contienen las&lt;br /&gt;
declaraciones necesarias en su archivo ASM principal. Mantén juntos&lt;br /&gt;
el ASM, el JSON y las carpetas incluidas con el recurso para no romper&lt;br /&gt;
sus rutas relativas.&lt;br /&gt;
&lt;br /&gt;
=== Carpetas tradicionales ===&lt;br /&gt;
&lt;br /&gt;
Algunos recursos utilizan las carpetas tradicionales de Dynamic&lt;br /&gt;
Xtreme. En ese caso, sigue esta organización:&lt;br /&gt;
&lt;br /&gt;
Estas carpetas se encuentran junto al ejecutable de Dynamic Xtreme: &amp;lt;code&amp;gt;dxt.exe&amp;lt;/code&amp;gt; en Windows o &amp;lt;code&amp;gt;dxt&amp;lt;/code&amp;gt; en Linux.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tipo de archivo&lt;br /&gt;
! Carpeta&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;DynamicInfos&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;DrawInfos&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteEffects&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gráficos, paletas y otros archivos relacionados&lt;br /&gt;
| &amp;lt;code&amp;gt;DynamicResources&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Utiliza siempre el método indicado por el recurso. No muevas a las&lt;br /&gt;
carpetas tradicionales los archivos de un sprite o código UberASM&lt;br /&gt;
moderno, salvo que sus instrucciones lo soliciten.&lt;br /&gt;
&lt;br /&gt;
== Instalación completa ==&lt;br /&gt;
&lt;br /&gt;
=== Ejecutar la herramienta ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme debe ejecutarse desde su propia carpeta.&lt;br /&gt;
&lt;br /&gt;
* En Windows, haz doble clic en &amp;lt;code&amp;gt;dxt.exe&amp;lt;/code&amp;gt;.&lt;br /&gt;
* En Linux, abre una terminal en la carpeta de Dynamic Xtreme y ejecuta:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./dxt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La herramienta mostrará una serie de preguntas para configurar la&lt;br /&gt;
instalación.&lt;br /&gt;
&lt;br /&gt;
=== Configurar las rutas ===&lt;br /&gt;
&lt;br /&gt;
Las rutas y las funcionalidades seleccionadas quedan guardadas en &amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt;, dentro de la carpeta de Dynamic Xtreme. La herramienta utiliza ese archivo para recuperar la configuración en las siguientes instalaciones.&lt;br /&gt;
&lt;br /&gt;
Puedes escribir cada ruta o arrastrar el archivo correspondiente a la&lt;br /&gt;
terminal. Después, presiona Enter para continuar.&lt;br /&gt;
&lt;br /&gt;
Si dejas una respuesta vacía y presionas Enter, Dynamic Xtreme&lt;br /&gt;
utilizará el valor guardado en &amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt;. Si todavía no&lt;br /&gt;
existe un valor guardado y la ruta es opcional, esa integración se&lt;br /&gt;
omitirá.&lt;br /&gt;
&lt;br /&gt;
Las rutas se solicitan en el siguiente orden:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;ROM de entrada&#039;&#039;&#039;&lt;br /&gt;
#: Selecciona la ROM de Super Mario World que deseas modificar.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;ROM de salida&#039;&#039;&#039;&lt;br /&gt;
#: Indica la ruta de la ROM que tendrá el resultado de la instalación.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Ejecutable de PIXI&#039;&#039;&#039;&lt;br /&gt;
#: Selecciona el ejecutable de PIXI. Esta ruta permite integrar las&lt;br /&gt;
#: rutinas y definiciones de Dynamic Xtreme con PIXI.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Ejecutable de UberASMTool&#039;&#039;&#039;&lt;br /&gt;
#: Selecciona el ejecutable de UberASMTool si tu proyecto utiliza&lt;br /&gt;
#: códigos de UberASM.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Ejecutable de GPS&#039;&#039;&#039;&lt;br /&gt;
#: Selecciona el ejecutable de GPS si tu proyecto utiliza bloques&lt;br /&gt;
#: personalizados.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Lista de PIXI&#039;&#039;&#039;&lt;br /&gt;
#: Selecciona el archivo de lista donde registraste los sprites que&lt;br /&gt;
#: utilizará tu proyecto.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Lista de UberASMTool&#039;&#039;&#039;&lt;br /&gt;
#: Selecciona el archivo de lista donde registraste los códigos&lt;br /&gt;
#: UberASM que utilizará tu proyecto.&lt;br /&gt;
&lt;br /&gt;
Las rutas de PIXI, UberASMTool, GPS y sus listas son opcionales.&lt;br /&gt;
Si no utilizas alguna de estas herramientas y no existe una ruta&lt;br /&gt;
guardada, puedes dejar la respuesta vacía.&lt;br /&gt;
&lt;br /&gt;
Para dejar de utilizar una integración que ya tiene rutas guardadas, edita &amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt; y deja sus valores como cadenas vacías (&amp;lt;code&amp;gt;&amp;quot;&amp;quot;&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
* PIXI: &amp;lt;code&amp;gt;PixiPath&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PixiListPath&amp;lt;/code&amp;gt;.&lt;br /&gt;
* UberASMTool: &amp;lt;code&amp;gt;UberasmToolPath&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;UberasmListPath&amp;lt;/code&amp;gt;.&lt;br /&gt;
* GPS: &amp;lt;code&amp;gt;GPSPath&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
No elimines los campos ni reemplaces todo el archivo. En las siguientes preguntas podrás dejar esas rutas vacías sin recuperar la integración anterior.&lt;br /&gt;
&lt;br /&gt;
=== Seleccionar las funciones ===&lt;br /&gt;
&lt;br /&gt;
Después de configurar las rutas, Dynamic Xtreme preguntará qué&lt;br /&gt;
funciones deseas instalar.&lt;br /&gt;
&lt;br /&gt;
Puedes responder &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt; para habilitar una función o&lt;br /&gt;
&amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; para deshabilitarla.&lt;br /&gt;
&lt;br /&gt;
Si presionas Enter sin escribir nada, se conservará el valor guardado&lt;br /&gt;
en &amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt;. Durante la primera instalación se utilizará&lt;br /&gt;
el valor predeterminado de la función.&lt;br /&gt;
&lt;br /&gt;
En una instalación habitual se pueden habilitar las funciones que no&lt;br /&gt;
muestran advertencias. Si aparece una advertencia en rojo, léela con&lt;br /&gt;
atención y comprueba su compatibilidad con tu proyecto antes de&lt;br /&gt;
habilitar esa función.&lt;br /&gt;
&lt;br /&gt;
Consulta [[es/Dynamic_Xtreme#Funcionalidades|Funcionalidades]] para saber qué hace cada opción y [[es/Dynamic_Xtreme#Compatibilidad|Compatibilidad]] para revisar los posibles conflictos con otros recursos y los espacios de RAM utilizados.&lt;br /&gt;
&lt;br /&gt;
=== Ejemplo de instalación típica con PIXI y UberASMTool ===&lt;br /&gt;
&lt;br /&gt;
Este ejemplo utiliza PIXI y UberASMTool con las opciones predeterminadas. Las rutas son ficticias y corresponden a Windows; sustitúyelas por las de tu proyecto. En Linux, indica las rutas de sus ejecutables correspondientes.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Pregunta !! Ejemplo de respuesta&lt;br /&gt;
|-&lt;br /&gt;
| ROM de entrada || &amp;lt;code&amp;gt;C:\MiHack\MiHack.smc&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| ROM de salida || &amp;lt;code&amp;gt;C:\MiHack\MiHack_DX.smc&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ejecutable de PIXI || &amp;lt;code&amp;gt;C:\MiHack\PIXI\pixi.exe&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ejecutable de UberASMTool || &amp;lt;code&amp;gt;C:\MiHack\UberASMTool\UberASMTool.exe&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ejecutable de GPS || Dejar vacío si no se utiliza y no hay una ruta guardada.&lt;br /&gt;
|-&lt;br /&gt;
| Lista de PIXI || &amp;lt;code&amp;gt;C:\MiHack\PIXI\list.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Lista de UberASMTool || &amp;lt;code&amp;gt;C:\MiHack\UberASMTool\list.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para las funcionalidades, utiliza estos valores:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Activada !! Respuesta&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt; || No || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt; || No || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; || No || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; || No || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
En ROMs con SA-1, &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; se desactiva automáticamente.&lt;br /&gt;
&lt;br /&gt;
Enter conserva el valor guardado si ya utilizaste la herramienta. Para reproducir esta configuración, responde &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; según la tabla; los valores predeterminados solo se utilizan cuando no hay una selección anterior.&lt;br /&gt;
&lt;br /&gt;
== Instalación mediante línea de comandos ==&lt;br /&gt;
&lt;br /&gt;
Después de completar una instalación interactiva, Dynamic Xtreme&lt;br /&gt;
guarda las rutas y funciones seleccionadas en&lt;br /&gt;
&amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Puedes reutilizar esa configuración para realizar instalaciones&lt;br /&gt;
posteriores sin responder nuevamente todas las preguntas.&lt;br /&gt;
&lt;br /&gt;
En Windows, abre una terminal en la carpeta de Dynamic Xtreme y&lt;br /&gt;
ejecuta:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.\dxt.exe -use-settings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En Linux, ejecuta:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./dxt -use-settings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si alguna ruta guardada ya no es válida, Dynamic Xtreme volverá al&lt;br /&gt;
modo interactivo para solicitar la configuración.&lt;br /&gt;
&lt;br /&gt;
Las opciones disponibles son:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Opción&lt;br /&gt;
! Alias&lt;br /&gt;
! Descripción&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-use-settings&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;-us&amp;lt;/code&amp;gt;&lt;br /&gt;
| Utiliza las rutas y funciones guardadas sin mostrar nuevamente las&lt;br /&gt;
preguntas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-verbose&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;-v&amp;lt;/code&amp;gt;&lt;br /&gt;
| Muestra información más detallada durante la instalación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-help&amp;lt;/code&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
| Muestra la ayuda y la lista de opciones disponibles.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-version&amp;lt;/code&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
| Muestra la versión instalada de Dynamic Xtreme.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las opciones pueden combinarse. Por ejemplo, para utilizar la&lt;br /&gt;
configuración guardada y mostrar información detallada:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Windows:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.\dxt.exe -use-settings -verbose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Linux:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./dxt -use-settings -verbose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para cambiar las rutas o las funciones seleccionadas, ejecuta Dynamic&lt;br /&gt;
Xtreme sin &amp;lt;code&amp;gt;-use-settings&amp;lt;/code&amp;gt; y completa nuevamente las&lt;br /&gt;
preguntas.&lt;br /&gt;
&lt;br /&gt;
== Finalizar la instalación ==&lt;br /&gt;
&lt;br /&gt;
Tanto la instalación interactiva como la instalación mediante línea&lt;br /&gt;
de comandos producen el mismo resultado.&lt;br /&gt;
&lt;br /&gt;
El resultado de la instalación queda guardado en &amp;lt;code&amp;gt;log.txt&amp;lt;/code&amp;gt;, junto al ejecutable de Dynamic Xtreme. Este archivo contiene todos los detalles de la instalación.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme prepara la integración con PIXI, UberASMTool y GPS,&lt;br /&gt;
pero no ejecuta estas herramientas. Después de instalar Dynamic&lt;br /&gt;
Xtreme, vuelve a ejecutar las herramientas externas que utilice tu&lt;br /&gt;
proyecto sobre la ROM de salida.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cuándo reinstalar:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Si cambias gráficos, paletas o archivos &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;, reinstala Dynamic Xtreme y después las herramientas que utilicen esos recursos.&lt;br /&gt;
* Si añades, eliminas o modificas los includes de recursos &amp;lt;code&amp;gt;;#incdyn&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;;#incdri&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;;#incpale&amp;lt;/code&amp;gt; dentro del ASM, también debes reinstalar Dynamic Xtreme y después las herramientas que utilicen esos recursos.&lt;br /&gt;
* Si solo modificas el código &amp;lt;code&amp;gt;*.asm&amp;lt;/code&amp;gt;, sin cambiar esos includes, no necesitas reinstalar Dynamic Xtreme. Basta con volver a insertar el código con la herramienta correspondiente.&lt;br /&gt;
&lt;br /&gt;
Cuando sea necesario reinstalar Dynamic Xtreme, el orden correcto es:&lt;br /&gt;
&lt;br /&gt;
# Ejecutar Dynamic Xtreme para regenerar e instalar sus recursos.&lt;br /&gt;
# Volver a ejecutar PIXI, UberASMTool, GPS y cualquier otra&lt;br /&gt;
#: herramienta que utilice datos generados por Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Este orden es necesario porque las direcciones y los identificadores&lt;br /&gt;
de los recursos pueden cambiar cada vez que se ejecuta Dynamic&lt;br /&gt;
Xtreme.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_sprite_creation_guide&amp;diff=21382</id>
		<title>es/Dynamic Xtreme sprite creation guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_sprite_creation_guide&amp;diff=21382"/>
		<updated>2026-10-25T17:14:52Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_sprite_creation_guide}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explicará cómo crear sprites dinámicos utilizando Dynamic Xtreme y PIXI.&lt;br /&gt;
&lt;br /&gt;
La guía recorrerá el proceso completo: preparar los gráficos, definir las poses, incluir los archivos necesarios en el sprite y utilizar el sistema para cargar y dibujar sus poses en pantalla.&lt;br /&gt;
&lt;br /&gt;
Si tienes dudas sobre los registros, parámetros o valores devueltos por una llamada, consulta la [[es/Dynamic_Xtreme_ASM_API|API ASM]]. Los apartados de esta guía incluyen enlaces a las llamadas correspondientes.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
Para seguir esta guía necesitas:&lt;br /&gt;
&lt;br /&gt;
* Tener [https://www.smwcentral.net/?p=section&amp;amp;s=tools&amp;amp;f%5Bname%5D=PIXI PIXI] instalado y configurado para insertar sprites en tu ROM.&lt;br /&gt;
* Tener Dynamic Xtreme instalado y configurado. Si todavía no lo has hecho, consulta la [[Dynamic_Xtreme_Quick_Start|guía de inicio rápido]].&lt;br /&gt;
&lt;br /&gt;
== Archivos utilizados por un sprite dinámico ==&lt;br /&gt;
&lt;br /&gt;
Además de los archivos utilizados normalmente por PIXI, un sprite dinámico necesita los siguientes archivos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Archivo gráfico (*.bin):&#039;&#039;&#039; contiene los gráficos de las poses del sprite.&lt;br /&gt;
* &#039;&#039;&#039;DynamicInfo (*.dynamicinfo):&#039;&#039;&#039; indica qué gráficos utiliza el sprite y cómo se dividen en poses.&lt;br /&gt;
* &#039;&#039;&#039;DrawInfo (*.drawinfo):&#039;&#039;&#039; contiene la información necesaria para dibujar las poses.&lt;br /&gt;
* &#039;&#039;&#039;Archivo ASM (*.asm):&#039;&#039;&#039; contiene el código del sprite y utiliza los recursos anteriores.&lt;br /&gt;
&lt;br /&gt;
Una posible estructura consiste en guardar los archivos de Dynamic Xtreme junto al propio recurso de PIXI. Por ejemplo, un sprite normal podría organizarse de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PIXI/&lt;br /&gt;
└── sprites/&lt;br /&gt;
    └── MySprite/&lt;br /&gt;
        ├── MySprite.asm&lt;br /&gt;
        ├── MySprite.json&lt;br /&gt;
        └── DynamicXtreme/&lt;br /&gt;
            ├── MySprite.bin&lt;br /&gt;
            ├── MySprite.dynamicinfo&lt;br /&gt;
            └── MySprite.drawinfo&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El archivo ASM y el archivo de configuración permanecen en la carpeta principal del sprite. Los gráficos, el DynamicInfo y el DrawInfo se guardan dentro de la subcarpeta &amp;lt;code&amp;gt;DynamicXtreme&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
En este caso, el ASM principal del sprite debe incluir el DynamicInfo y el DrawInfo mediante las siguientes directivas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MySprite.dynamicinfo&amp;quot;&lt;br /&gt;
;#incdri &amp;quot;DynamicXtreme/MySprite.drawinfo&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las rutas son relativas al archivo ASM que contiene las directivas. Si se trabaja con un cluster sprite, extended sprite u otro tipo admitido por PIXI, la carpeta completa del recurso puede organizarse de la misma manera dentro de la carpeta correspondiente de PIXI.&lt;br /&gt;
&lt;br /&gt;
También es posible utilizar las carpetas tradicionales de Dynamic Xtreme. En ese caso, el archivo &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt; se coloca en &amp;lt;code&amp;gt;DynamicInfos&amp;lt;/code&amp;gt;, el archivo &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DrawInfos&amp;lt;/code&amp;gt; y los gráficos &amp;lt;code&amp;gt;*.bin&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DynamicResources&amp;lt;/code&amp;gt;. Los archivos guardados de esta forma son encontrados directamente por Dynamic Xtreme y no necesitan las directivas &amp;lt;code&amp;gt;;#incdyn&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;;#incdri&amp;lt;/code&amp;gt; en el sprite.&lt;br /&gt;
&lt;br /&gt;
La primera opción facilita distribuir el sprite con todos sus recursos dentro de una sola carpeta, mientras que la segunda mantiene la organización tradicional de Dynamic Xtreme. Para conocer la estructura y las reglas de cada formato, consulta [[Dynamic_Xtreme_files_and_formats|Archivos y formatos de Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
Durante la instalación, Dynamic Xtreme genera los defines que utilizará el código del sprite y los guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Esta tabla resume el origen de los nombres utilizados en la guía:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define de ejemplo !! De dónde sale !! Para qué se utiliza&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt;&lt;br /&gt;
| Los límites horizontales de las poses de &amp;lt;code&amp;gt;MySprite.drawinfo&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Configurar la distancia horizontal del RenderBox en el INIT.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt;&lt;br /&gt;
| Los límites verticales de las poses de &amp;lt;code&amp;gt;MySprite.drawinfo&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Configurar la distancia vertical del RenderBox en el INIT.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt;&lt;br /&gt;
| La lista &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;MySprite.dynamicinfo&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Indicar a la asignación de paletas qué tabla utilizar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt;&lt;br /&gt;
| La primera pose de los gráficos &amp;lt;code&amp;gt;MySprite.bin&amp;lt;/code&amp;gt;, declarados en &amp;lt;code&amp;gt;PosesGraphics&amp;lt;/code&amp;gt; del DynamicInfo.&lt;br /&gt;
| Solicitar los gráficos de esa pose mediante &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. El sufijo &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; identifica la primera pose de ese archivo gráfico; &amp;lt;code&amp;gt;003&amp;lt;/code&amp;gt;, la cuarta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt;&lt;br /&gt;
| La pose &amp;lt;code&amp;gt;Frame0&amp;lt;/code&amp;gt; declarada en &amp;lt;code&amp;gt;MySprite.drawinfo&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Seleccionar la pose que dibujará &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt;&lt;br /&gt;
| El primer efecto de &amp;lt;code&amp;gt;MyEffect.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
| Seleccionar el efecto de paleta que se aplicará.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres se normalizan eliminando separadores y escribiendo en mayúscula la inicial de cada palabra: por ejemplo, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Consulta siempre los nombres exactos generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; la guía también recuerda su origen junto a cada uso.&lt;br /&gt;
&lt;br /&gt;
== Estructura del sprite ==&lt;br /&gt;
&lt;br /&gt;
Un sprite dinámico conserva la estructura habitual de un sprite de PIXI, pero debe preparar las variables utilizadas por Dynamic Xtreme y organizar su rutina principal según se encuentre dentro o fuera de su área de renderizado.&lt;br /&gt;
&lt;br /&gt;
La estructura que se utilizará en esta guía se divide en las siguientes partes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;INIT:&#039;&#039;&#039; inicializa las variables del sprite y el estado utilizado por Dynamic Xtreme.&lt;br /&gt;
* &#039;&#039;&#039;Short routine:&#039;&#039;&#039; ejecuta la lógica que debe continuar incluso cuando el sprite se encuentra fuera del área de renderizado.&lt;br /&gt;
* &#039;&#039;&#039;Long routine:&#039;&#039;&#039; maneja las tareas que solamente son necesarias dentro del área de renderizado, como solicitar la pose y dibujarla.&lt;br /&gt;
&lt;br /&gt;
=== Incluir los defines del tipo de sprite ===&lt;br /&gt;
&lt;br /&gt;
Antes del código del sprite se debe incluir el archivo de defines correspondiente al tipo de recurso utilizado:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt; para sprites normales.&lt;br /&gt;
* &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; para cluster sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; para extended sprites.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si el ASM de un sprite normal se encuentra dentro de una subcarpeta de &amp;lt;code&amp;gt;sprites&amp;lt;/code&amp;gt;, el include puede escribirse de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
incsrc &amp;quot;../NormalSpriteDefines.asm&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La ruta siempre es relativa a la ubicación del archivo ASM del sprite, por lo que debe ajustarse a la estructura de carpetas utilizada por el recurso. Este archivo proporciona los aliases de tablas y rutinas correspondientes a su tipo de sprite; gracias a esto, nombres como &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; apuntan a la implementación correcta para un sprite normal, cluster o extended.&lt;br /&gt;
&lt;br /&gt;
=== INIT ===&lt;br /&gt;
&lt;br /&gt;
En los sprites normales, la rutina &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; debe establecer las distancias utilizadas por el &amp;lt;code&amp;gt;RenderBox&amp;lt;/code&amp;gt;, asignar los valores iniciales del sprite e invalidar cualquier estado anterior que pueda permanecer en el mismo slot de PIXI.&lt;br /&gt;
&lt;br /&gt;
El siguiente ejemplo corresponde a un sprite normal. Inicia el sprite con la pose 0 y obtiene la versión y el volteo inicial desde la configuración de PIXI:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
print &amp;quot;INIT &amp;quot;,pc&lt;br /&gt;
    LDA.b #!RenderBoxXDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderXDistanceOutOfScreen,x&lt;br /&gt;
    LDA.b #!RenderBoxYDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderYDistanceOutOfScreen,x&lt;br /&gt;
&lt;br /&gt;
    LDA !ExtraBits,x&lt;br /&gt;
    AND #$04&lt;br /&gt;
    LSR&lt;br /&gt;
    LSR&lt;br /&gt;
    STA !GlobalFlip,x&lt;br /&gt;
&lt;br /&gt;
    LDA !ExtraByte1,x&lt;br /&gt;
    AND #$0F&lt;br /&gt;
    STA !Version,x&lt;br /&gt;
&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    STA !PoseIndex,x&lt;br /&gt;
    STA !LocalFlip,x&lt;br /&gt;
    STA !LastFlip,x&lt;br /&gt;
&lt;br /&gt;
    LDA #$FF&lt;br /&gt;
    STA !Palette,x&lt;br /&gt;
    STA !LastPoseIndex,x&lt;br /&gt;
    STA !LastPoseHashIndex,x&lt;br /&gt;
    STA !LastVersion,x&lt;br /&gt;
&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cada variable del ejemplo cumple una función concreta:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen&amp;lt;/code&amp;gt; guardan las distancias que utilizará &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; para decidir si el sprite todavía se encuentra lo bastante cerca de la pantalla como para renderizarse. Los valores &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; son generados a partir del DrawInfo y quedan disponibles en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre del recurso se normaliza para formar el define: se eliminan separadores como espacios y guiones bajos, y la inicial de cada palabra se escribe en mayúscula. Por ejemplo, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;my sprite&amp;lt;/code&amp;gt; se convierten en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; indica la pose dinámica que el sprite desea utilizar dentro del DynamicInfo. El valor 0 selecciona la primera pose del recurso. Una rutina de animación puede asignar otro valor antes de solicitar los gráficos.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt; identifica la variante actual del sprite. Una versión puede cambiar su paleta, sus gráficos o incluso su comportamiento. En los sprites normales es habitual tomarla de los cuatro bits bajos de &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt;, lo que permite seleccionar hasta 16 versiones distintas desde Lunar Magic.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip&amp;lt;/code&amp;gt; representa el volteo general del sprite. En los sprites normales puede obtenerse del extra bit: 0 mantiene la orientación original y 1 aplica el volteo inicial. &amp;lt;code&amp;gt;!LocalFlip&amp;lt;/code&amp;gt; permite aplicar un volteo adicional a la pose actual. Dynamic Xtreme combina ambos valores y conserva en &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt; el volteo efectivo utilizado para dibujar.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt; guarda la paleta asignada actualmente. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; porque el sprite todavía no posee una paleta válida.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; guarda la última pose que Dynamic Xtreme pudo obtener correctamente, y &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; guarda el slot de la caché de VRAM donde se encuentra. Ambos comienzan en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; porque todavía no existe una pose disponible.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt; guarda la versión procesada anteriormente por el manejo de paletas. Iniciarla en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; hace que la primera versión del sprite sea procesada aunque &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt; comience en 0.&lt;br /&gt;
&lt;br /&gt;
Si un sprite utiliza varios DrawInfo, las distancias deben cubrir el conjunto completo de sus gráficos. Se recomienda revisar en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; los valores generados para cada DrawInfo y utilizar la mayor distancia horizontal y la mayor distancia vertical. Por ejemplo, si la cabeza y el cuerpo utilizan DrawInfo diferentes, tomar solamente las distancias de la cabeza podría hacer que el sprite deje de dibujarse cuando una parte de su cuerpo todavía se encuentra dentro de la pantalla.&lt;br /&gt;
&lt;br /&gt;
Los valores marcados con &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; representan estados inválidos. Además de indicar que el sprite todavía no tiene una paleta o pose disponible, evitan reutilizar información dejada por otro sprite que haya ocupado anteriormente el mismo slot de PIXI.&lt;br /&gt;
&lt;br /&gt;
==== Inicialización de cluster y extended sprites ====&lt;br /&gt;
&lt;br /&gt;
Los cluster sprites y extended sprites no tienen una rutina &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; propia. Para inicializarlos una sola vez se reserva una de sus tablas, por ejemplo &amp;lt;code&amp;gt;!ClusterMiscTable1&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!ExtendedMiscTable1&amp;lt;/code&amp;gt;, y se le asigna un nombre como &amp;lt;code&amp;gt;!Started&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!Started = !ClusterMiscTable1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cuando se crea el sprite, &amp;lt;code&amp;gt;!Started&amp;lt;/code&amp;gt; debe establecerse en 0 utilizando el índice del nuevo cluster o extended sprite. Esto es necesario porque el slot pudo haber sido utilizado anteriormente y todavía podría contener el valor de otro sprite.&lt;br /&gt;
&lt;br /&gt;
Al comienzo de &amp;lt;code&amp;gt;SpriteCode&amp;lt;/code&amp;gt;, antes de ejecutar &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;, se comprueba esta variable:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpriteCode:&lt;br /&gt;
    LDA !Started,x&lt;br /&gt;
    BNE +&lt;br /&gt;
    JSR Start&lt;br /&gt;
    RTS&lt;br /&gt;
+&lt;br /&gt;
    !RenderBox&lt;br /&gt;
    ; Resto del código del sprite&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;Start&amp;lt;/code&amp;gt; contiene la inicialización que un sprite normal realizaría en &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt;. Al finalizar, establece &amp;lt;code&amp;gt;!Started&amp;lt;/code&amp;gt; en 1 para que no vuelva a ejecutarse durante los frames siguientes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Start:&lt;br /&gt;
    ; Aquí va la inicialización del sprite&lt;br /&gt;
&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !Started,x&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Como &amp;lt;code&amp;gt;Start&amp;lt;/code&amp;gt; se llama mediante &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;, debe terminar con &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;. El código que crea el cluster o extended sprite también debe preparar cualquier dato que deba heredarse del sprite principal, como &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!GlobalFlip&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== PaletteOption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; controla la paleta solicitada y si esta será afectada por el efecto global de paleta. Su formato es el siguiente:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EPPP----&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; indica si la paleta será afectada por el efecto global: 0 la excluye y 1 lo habilita.&lt;br /&gt;
* &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; representa una paleta entre 8 y F: &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; corresponde a la paleta 8 y &amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt; a la paleta F.&lt;br /&gt;
* Los cuatro bits bajos no forman parte de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cuando se utiliza asignación automática, &amp;lt;code&amp;gt;PPP = 000&amp;lt;/code&amp;gt; permite buscar un slot libre entre las ocho paletas, un valor &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; limita la búsqueda a las paletas 8-B y un valor &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; la limita a las paletas C-F. Con asignación manual, &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; selecciona directamente la paleta que se utilizará.&lt;br /&gt;
&lt;br /&gt;
En los sprites normales, &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; utiliza directamente &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt;. Lo habitual es aprovechar los cuatro bits restantes para seleccionar la versión del sprite, por lo que el byte completo utiliza el siguiente formato:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EPPPVVVV&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;EPPP&amp;lt;/code&amp;gt; contiene las opciones de paleta descritas anteriormente.&lt;br /&gt;
* &amp;lt;code&amp;gt;VVVV&amp;lt;/code&amp;gt; selecciona una de las 16 versiones posibles del sprite, desde 0 hasta 15.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; utiliza los cuatro bits altos directamente, mientras que el &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; copia los cuatro bits bajos a &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt;. No es necesario copiar &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; a otra tabla.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignmentOption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; determina cómo se asignará la paleta al sprite:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--AA----&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 00&amp;lt;/code&amp;gt;: &#039;&#039;&#039;asignación automática&#039;&#039;&#039;. Dynamic Xtreme busca un slot permitido por &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; y carga la paleta dinámicamente.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 01&amp;lt;/code&amp;gt;: &#039;&#039;&#039;asignación manual&#039;&#039;&#039;. &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; indica el slot exacto y Dynamic Xtreme carga la paleta dinámicamente.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 10&amp;lt;/code&amp;gt;: &#039;&#039;&#039;asignación manual sin carga&#039;&#039;&#039;. El sprite utiliza directamente la paleta que ya existe en el nivel y Dynamic Xtreme no carga una nueva.&lt;br /&gt;
&lt;br /&gt;
En los sprites normales, &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; utiliza directamente &amp;lt;code&amp;gt;!ExtraProp2,x&amp;lt;/code&amp;gt;. Por lo tanto, el modo se configura mediante los bits 5 y 4 del Extra Property Byte 2 y tampoco necesita copiarse a otra tabla durante el &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
En los cluster sprites y extended sprites, &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; deben establecerse manualmente cuando son creados. Normalmente se copia el modo de asignación del sprite que los genera. Al copiar &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;, sus cuatro bits bajos deben borrarse porque en un sprite normal contienen la versión y no forman parte de la opción de paleta.&lt;br /&gt;
&lt;br /&gt;
Si el sprite generado utiliza la misma paleta que el sprite principal, puede copiar su &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; después de borrar los cuatro bits bajos. Si utiliza una paleta distinta y el sprite principal emplea asignación automática, puede conservarse el mismo rango de búsqueda. Si el sprite principal emplea asignación manual o asignación manual sin carga, se suma &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; al valor enmascarado para seleccionar la paleta siguiente.&lt;br /&gt;
&lt;br /&gt;
En este último caso, el sprite principal no puede utilizar la paleta F, porque el sprite generado necesita la paleta siguiente. Debes configurar el sprite principal con una paleta entre la 8 y la E.&lt;br /&gt;
&lt;br /&gt;
Además de estas variables, el &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; puede inicializar cualquier tabla propia que necesite el comportamiento del sprite.&lt;br /&gt;
&lt;br /&gt;
=== SpriteCode ===&lt;br /&gt;
&lt;br /&gt;
Consulta en la API las entradas y el resultado de [[es/Dynamic_Xtreme_ASM_API#RenderBox|RenderBox]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SpriteCode&amp;lt;/code&amp;gt; comienza ejecutando &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;. Esta rutina devuelve el carry activado cuando el sprite se encuentra dentro de su área de renderizado y desactivado cuando está fuera de ella. Con este resultado se decide si ejecutar la short routine o la long routine.&lt;br /&gt;
&lt;br /&gt;
Una estructura base puede escribirse de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpriteCode:&lt;br /&gt;
    !RenderBox&lt;br /&gt;
    BCS .LongRoutine&lt;br /&gt;
&lt;br /&gt;
.ShortRoutine&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    %SubOffScreen()&lt;br /&gt;
    ; Aquí va la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&lt;br /&gt;
.LongRoutine&lt;br /&gt;
    JSR PaletteManagement&lt;br /&gt;
    BCC ..Return&lt;br /&gt;
&lt;br /&gt;
    JSR PoseManagement&lt;br /&gt;
    BCC ..Return&lt;br /&gt;
&lt;br /&gt;
    JSR Draw&lt;br /&gt;
    ; Aquí va la lógica de tu sprite&lt;br /&gt;
..Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Short routine ====&lt;br /&gt;
&lt;br /&gt;
La short routine se ejecuta cuando el sprite se encuentra fuera del área calculada por &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;. Aquí solamente debe ejecutarse la lógica base necesaria para mantener el comportamiento del sprite, sin solicitar gráficos dinámicos, procesar su paleta ni dibujarlo. El contenido exacto depende del sprite y puede incluir su movimiento, estado, temporizadores, interacciones o animación.&lt;br /&gt;
&lt;br /&gt;
En los sprites normales se recomienda llamar a &amp;lt;code&amp;gt;%SubOffScreen()&amp;lt;/code&amp;gt; dentro de esta parte. 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. De esta manera PIXI puede eliminar el sprite cuando se aleja lo suficiente de la pantalla, sin ejecutar esta comprobación durante la parte más costosa del renderizado.&lt;br /&gt;
&lt;br /&gt;
==== Long routine ====&lt;br /&gt;
&lt;br /&gt;
La long routine se ejecuta cuando el sprite está dentro del área de renderizado. Esta ruta realiza el proceso completo: maneja la paleta, solicita la pose dinámica o actualiza su registro de uso si ya está en VRAM para evitar que sea sobrescrita, dibuja el sprite y finalmente ejecuta la misma lógica base de la short routine.&lt;br /&gt;
&lt;br /&gt;
No es necesario llamar nuevamente a &amp;lt;code&amp;gt;%SubOffScreen()&amp;lt;/code&amp;gt; dentro de la long routine. Como &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; ya determinó que el sprite se encuentra dentro del área de renderizado, realizar allí la comprobación resulta redundante.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;PaletteManagement&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PoseManagement&amp;lt;/code&amp;gt; devuelven el carry activado cuando existe un recurso utilizable. Si alguna de ellas devuelve el carry desactivado, el ejemplo salta a &amp;lt;code&amp;gt;..Return&amp;lt;/code&amp;gt; y termina la rutina. En ese caso, no se dibuja el sprite ni se ejecuta la lógica que viene después durante ese frame.&lt;br /&gt;
&lt;br /&gt;
Las rutinas de paleta, poses y dibujo se desarrollarán en los apartados siguientes. Los nombres utilizados aquí son solamente una forma de organizar el código y pueden cambiarse según la estructura del sprite.&lt;br /&gt;
&lt;br /&gt;
== Manejo de Paleta de Colores ==&lt;br /&gt;
&lt;br /&gt;
=== Cargar una paleta dinámica ===&lt;br /&gt;
&lt;br /&gt;
Consulta en la API los detalles de [[es/Dynamic_Xtreme_ASM_API#PaletteAssignment|PaletteAssignment]].&lt;br /&gt;
&lt;br /&gt;
Para utilizar la asignación de paletas en un sprite normal, su archivo &amp;lt;code&amp;gt;*.cfg&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;*.json&amp;lt;/code&amp;gt; debe tener configurado al menos un Extra Byte:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extra Byte 1:&#039;&#039;&#039; proporciona &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; y, en el ejemplo de esta guía, sus cuatro bits bajos seleccionan &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Extra Property Byte 2:&#039;&#039;&#039; configura &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; mediante sus bits 5 y 4: &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; para asignación automática, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; para asignación manual y &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt; para asignación manual sin carga. Estos bits corresponden a los valores &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;, respectivamente; los demás bits pueden utilizarse para otras opciones del sprite.&lt;br /&gt;
&lt;br /&gt;
La carga de una paleta dinámica se realiza mediante &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;. Solamente se debe cargar en A, con 16 bits, el offset de la tabla de paletas generado para el recurso:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignment&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera a partir de las paletas declaradas en el DynamicInfo y queda disponible en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre del DynamicInfo se normaliza eliminando espacios, guiones bajos y otros separadores, y escribiendo en mayúscula la inicial de cada palabra. Por ejemplo, &amp;lt;code&amp;gt;my_sprite.dynamicinfo&amp;lt;/code&amp;gt; genera el componente &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt; para seleccionar una entrada de la tabla: la versión 0 utiliza la primera paleta, la versión 1 utiliza la segunda y así sucesivamente. También utiliza &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; para decidir dónde y cómo asignarla.&lt;br /&gt;
&lt;br /&gt;
La rutina devuelve el carry activado cuando existe una paleta utilizable y desactivado cuando todavía no fue posible obtenerla. Por esta razón, &amp;lt;code&amp;gt;SpriteCode&amp;lt;/code&amp;gt; comprueba el carry antes de continuar con la carga de poses y el dibujo. &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; debe ejecutarse en cada frame de la long routine para conservar la asignación mientras el sprite siga utilizándola.&lt;br /&gt;
&lt;br /&gt;
=== Seleccionar una paleta sin cambiar la versión del sprite ===&lt;br /&gt;
&lt;br /&gt;
La paleta de un sprite puede cambiar sin que su versión o su comportamiento tengan que cambiar. Por ejemplo, un sprite puede alternar entre su paleta normal y una segunda paleta durante una animación o un estado temporal. Mantener ambas paletas como recursos independientes también permite que la segunda sea reutilizada por otros sprites.&lt;br /&gt;
&lt;br /&gt;
Como &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; selecciona la entrada mediante &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt;, puede guardarse temporalmente la versión lógica del sprite, asignar el índice de la paleta deseada y restaurar después el valor original:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    LDA !Version,x&lt;br /&gt;
    PHA&lt;br /&gt;
&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !Version,x&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignment&lt;br /&gt;
&lt;br /&gt;
    PLA&lt;br /&gt;
    STA !Version,x&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; utiliza la entrada 2 de la tabla, pero el comportamiento del sprite conserva su versión original. De esta forma, la selección de la paleta queda separada de la variante lógica del personaje. &amp;lt;code&amp;gt;PLA&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;STA&amp;lt;/code&amp;gt; no alteran el carry, por lo que &amp;lt;code&amp;gt;PaletteManagement&amp;lt;/code&amp;gt; todavía devuelve correctamente el resultado de &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; utilizado aquí se genera desde el DynamicInfo y se encuentra en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa la misma normalización: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra, de modo que &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Concatenar un efecto local con el efecto global ===&lt;br /&gt;
&lt;br /&gt;
Consulta en la API los detalles de [[es/Dynamic_Xtreme_ASM_API#PaletteAssignmentNoUpload|PaletteAssignmentNoUpload]], [[es/Dynamic_Xtreme_ASM_API#ConcatenateRGBPaletteEffectToGlobal|ConcatenateRGBPaletteEffectToGlobal]] y [[es/Dynamic_Xtreme_ASM_API#ConcatenateHSLPaletteEffectToGlobal|ConcatenateHSLPaletteEffectToGlobal]].&lt;br /&gt;
&lt;br /&gt;
Cuando la paleta necesita un efecto propio que además debe combinarse con el efecto global de paleta, se utiliza &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; seguido de &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    PHY&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #$06&lt;br /&gt;
    TAY&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA PaletteEffects,y&lt;br /&gt;
&lt;br /&gt;
    PLY&lt;br /&gt;
    !ConcatenateRGBPaletteEffectToGlobal&lt;br /&gt;
&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&lt;br /&gt;
PaletteEffects:&lt;br /&gt;
    dw !PaletteEffectIDMyEffect0&lt;br /&gt;
    dw !PaletteEffectIDMyEffect1&lt;br /&gt;
    dw !PaletteEffectIDMyEffect2&lt;br /&gt;
    dw !PaletteEffectIDMyEffect3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; asigna la paleta y prepara su dirección base sin realizar todavía la carga final. También deja en Y la información que la rutina de concatenación necesita para decidir si debe reconstruir el efecto.&lt;br /&gt;
&lt;br /&gt;
En este ejemplo se utiliza &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;, el contador principal de frames de Super Mario World, para seleccionar uno de cuatro efectos. Como Y se necesita temporalmente para leer la tabla &amp;lt;code&amp;gt;PaletteEffects&amp;lt;/code&amp;gt;, primero se conserva con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; y se restaura con &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt;. El valor restaurado debe llegar sin modificaciones a la rutina de concatenación.&lt;br /&gt;
&lt;br /&gt;
Antes de concatenar, X debe contener el valor de &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, que ya representa el índice requerido por la rutina. A debe contener, con 16 bits, el ID del efecto local. En el ejemplo, Y se utiliza como índice para cargar ese ID desde una tabla, pero el ID finalmente se entrega en A.&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y se encuentra en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los defines &amp;lt;code&amp;gt;!PaletteEffectIDMyEffectX&amp;lt;/code&amp;gt; son generados a partir de un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; durante la instalación y se guardan en el mismo archivo. En ambos casos los nombres se normalizan eliminando espacios, guiones bajos y otros separadores, y escribiendo en mayúscula la inicial de cada palabra. Por ejemplo, &amp;lt;code&amp;gt;my_effect.paleffect&amp;lt;/code&amp;gt; genera el componente &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; corresponde al índice del efecto dentro de la colección.&lt;br /&gt;
&lt;br /&gt;
Se utiliza &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; para efectos que trabajan en RGB, como &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, y &amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt; para efectos que trabajan en HSL, como &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;. Para combinar el efecto local con el global, el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; debe estar activado. La rutina realiza internamente las conversiones necesarias cuando ambos efectos utilizan espacios de color diferentes. Para conocer el espacio de color de cada efecto, consulta [https://sneslab.net/wiki/es/Dynamic_Xtreme_files_and_formats#Tipos_de_efectos Tipos de efectos].&lt;br /&gt;
&lt;br /&gt;
La concatenación devuelve el carry activado cuando existe un resultado utilizable, incluido un resultado anterior usado como respaldo, y desactivado cuando esa paleta todavía no posee ningún resultado válido. Este carry debe conservarse para que &amp;lt;code&amp;gt;SpriteCode&amp;lt;/code&amp;gt; pueda decidir si continúa con el dibujo.&lt;br /&gt;
&lt;br /&gt;
== Manejo de Poses Dinámicas ==&lt;br /&gt;
&lt;br /&gt;
Las poses dinámicas se solicitan mediante &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;. Estas rutinas buscan la pose en la caché de VRAM y, si todavía no está disponible, solicitan su carga. Deben ejecutarse en cada frame de la long routine para mantener activa la pose que utiliza el sprite.&lt;br /&gt;
&lt;br /&gt;
=== Upload ===&lt;br /&gt;
&lt;br /&gt;
Consulta en la API los detalles de [[es/Dynamic_Xtreme_ASM_API#Upload|Upload]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; recibe en A, con 16 bits, el ID dinámico base del recurso y le suma el valor de &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    !Upload&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, si &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; contiene 0 se solicita la primera pose; si contiene 1 se solicita la pose siguiente, y así sucesivamente. Esto permite que la rutina de animación cambie solamente &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; mientras &amp;lt;code&amp;gt;PoseManagement&amp;lt;/code&amp;gt; conserva el mismo ID base.&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera a partir del DynamicInfo durante la instalación de Dynamic Xtreme y queda disponible en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones bajos y otros separadores, y escribiendo en mayúscula la inicial de cada palabra. Por ejemplo, &amp;lt;code&amp;gt;my_sprite.dynamicinfo&amp;lt;/code&amp;gt; genera el componente &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; devuelve el carry activado cuando existe una pose utilizable. Esta puede ser la pose solicitada durante el frame actual o la última pose válida del sprite, utilizada como respaldo mientras la nueva termina de cargarse. El carry se devuelve desactivado solamente cuando el sprite todavía no posee ninguna pose que pueda utilizar.&lt;br /&gt;
&lt;br /&gt;
Cuando la solicitud tiene éxito, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; guarda la pose realmente disponible y &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; guarda su posición dentro de la caché de VRAM. Por esta razón, el dibujo debe utilizar el estado de la última pose disponible y no asumir que &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; ya fue cargado.&lt;br /&gt;
&lt;br /&gt;
=== UploadWithoutPoseOffset ===&lt;br /&gt;
&lt;br /&gt;
Consulta en la API los detalles de [[es/Dynamic_Xtreme_ASM_API#UploadWithoutPoseOffset|UploadWithoutPoseOffset]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; también recibe un ID dinámico en A con 16 bits, pero lo utiliza directamente y no le suma &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite003&lt;br /&gt;
    !UploadWithoutPoseOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esta variante es útil cuando el código ya seleccionó el ID dinámico exacto, por ejemplo mediante una tabla o una condición propia. Su carry tiene el mismo significado que en &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;: activado cuando existe una pose utilizable y desactivado cuando todavía no existe ninguna.&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!DynamicPoseIDMySprite003&amp;lt;/code&amp;gt; también es generado desde el DynamicInfo y se encuentra en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre utiliza la misma normalización de estilo CamelCase: se eliminan los separadores y se escribe en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
Actualmente &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; está publicado por los archivos de defines para sprites normales y cluster sprites. Los extended sprites deben utilizar &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; junto con &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; mientras su archivo de defines no publique este alias.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; pertenecen al sistema de carga dinámica. No deben confundirse con los defines &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt; del DrawInfo, que se utilizan posteriormente para dibujar la pose.&lt;br /&gt;
&lt;br /&gt;
== Dibujar Poses en Pantalla ==&lt;br /&gt;
&lt;br /&gt;
Una vez que &amp;lt;code&amp;gt;PoseManagement&amp;lt;/code&amp;gt; ha obtenido una pose utilizable, esta puede dibujarse mediante &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt;. Ambas rutinas utilizan la posición, el volteo, la paleta y la pose dinámica que Dynamic Xtreme conserva para el sprite.&lt;br /&gt;
&lt;br /&gt;
Antes de llamar a cualquiera de las dos rutinas deben prepararse los siguientes valores:&lt;br /&gt;
&lt;br /&gt;
* A, con 16 bits, contiene el ID de la pose de dibujo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; contiene propiedades adicionales con el formato &amp;lt;code&amp;gt;YXCC----&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; indica la prioridad máxima que pueden utilizar los tiles de la pose.&lt;br /&gt;
&lt;br /&gt;
Los valores admitidos por &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; son:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;: prioridad máxima.&lt;br /&gt;
* &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt;: prioridad alta.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;: prioridad propia del tipo de sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;: prioridad mínima.&lt;br /&gt;
&lt;br /&gt;
=== DXDraw ===&lt;br /&gt;
&lt;br /&gt;
Consulta en la API los detalles de [[es/Dynamic_Xtreme_ASM_API#DXDraw|DXDraw]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; dibuja la pose tomando como origen la posición normal del sprite. Una rutina de dibujo básica puede escribirse de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDraw&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El valor de &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; se suma al primer ID de dibujo para seleccionar la pose que realmente se encuentra disponible. Es importante utilizar &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; y no &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;: mientras una pose nueva termina de cargarse, Dynamic Xtreme puede conservar la pose anterior como respaldo.&lt;br /&gt;
&lt;br /&gt;
Este ejemplo supone que las poses del DrawInfo siguen el mismo orden que las poses del DynamicInfo. Si el orden es diferente, el código debe convertir &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; al ID de dibujo correspondiente, por ejemplo mediante una tabla.&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; es generado a partir del DrawInfo durante la instalación y queda disponible en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres generados se normalizan eliminando espacios, guiones bajos y otros separadores, y escribiendo en mayúscula la inicial de cada palabra. Por ejemplo, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; genera el componente &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt; identifican poses de dibujo declaradas en un DrawInfo. No deben confundirse con los defines &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; del DynamicInfo, que se utilizan con &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; para solicitar los gráficos dinámicos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; combina las propiedades indicadas en &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt;, la paleta asignada y las propiedades propias de la pose. También utiliza &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; para localizar sus gráficos en la caché de VRAM. Si este valor contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, la rutina no dibuja nada.&lt;br /&gt;
&lt;br /&gt;
=== DXDrawWithOffset ===&lt;br /&gt;
&lt;br /&gt;
Consulta en la API los detalles de [[es/Dynamic_Xtreme_ASM_API#DXDrawWithOffset|DXDrawWithOffset]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; funciona de la misma forma, pero permite desplazar el dibujo con respecto a la posición del sprite. Los desplazamientos se entregan como valores de 8 bits con signo mediante &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$08&lt;br /&gt;
    STA !XOffsetParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$F8&lt;br /&gt;
    STA !YOffsetParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDrawWithOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, el dibujo se desplaza 8 píxeles hacia la derecha y 8 píxeles hacia arriba. Un valor positivo en X desplaza la pose hacia la derecha y uno negativo hacia la izquierda; en Y, un valor positivo la desplaza hacia abajo y uno negativo hacia arriba.&lt;br /&gt;
&lt;br /&gt;
El offset solamente modifica la posición donde se dibuja la pose. No cambia la posición real del sprite, su hitbox ni sus interacciones. Esto resulta útil para alinear gráficos, aplicar movimientos visuales o dibujar varias partes de una entidad desde una misma posición lógica.&lt;br /&gt;
&lt;br /&gt;
Al igual que en el ejemplo anterior, &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; es un define generado desde el DrawInfo y guardado en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre utiliza la normalización de Dynamic Xtreme: elimina separadores como espacios y guiones bajos, y escribe en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
=== DrawStatic ===&lt;br /&gt;
&lt;br /&gt;
Consulta en la API los detalles de [[es/Dynamic_Xtreme_ASM_API#DrawStatic|DrawStatic]].&lt;br /&gt;
&lt;br /&gt;
El sistema de dibujo de Dynamic Xtreme también puede utilizarse con poses estáticas. Estas poses se declaran mediante &amp;lt;code&amp;gt;.IsStatic&amp;lt;/code&amp;gt; en el DrawInfo y se dibujan con la macro &amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt;. Como sus gráficos ya se encuentran disponibles en la VRAM, no necesitan &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cuando una pose estática utiliza el tile predeterminado (0) para todos sus componentes, el dibujo toma el número de tile desde &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, que representa la scratch RAM &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;. Esto permite reutilizar una misma pose, por ejemplo una de un solo tile, para dibujar distintos gráficos. El sprite debe preparar el valor antes de llamar a &amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    LDA #$80            ; Número de tile que se desea dibujar&lt;br /&gt;
    STA !Tile           ; Scratch RAM $05&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Este valor debe prepararse en cada llamada de dibujo que lo necesite; no basta con establecerlo durante el INIT, porque la scratch RAM se comparte con otras rutinas.&lt;br /&gt;
&lt;br /&gt;
En las poses dinámicas, &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; obtienen el tile desde la ubicación de los gráficos en la caché de VRAM. En ese caso no es necesario preparar &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; manualmente. Si una pose estática declara tiles distintos del predeterminado en su DrawInfo, el dibujo utiliza esos valores directamente.&lt;br /&gt;
&lt;br /&gt;
El siguiente ejemplo dibuja una pose estática en la posición de un sprite normal, sin volteo y utilizando la paleta A:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    REP #$21&lt;br /&gt;
    LDA #!PoseIDMyStaticSprite_Frame0&lt;br /&gt;
    %DrawStatic(0, 1, #$00, #$04, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El primer parámetro indica si se utilizarán offsets adicionales: 0 dibuja en la posición entregada y 1 aplica también &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt;. Los parámetros siguientes proporcionan el contexto del dibujo, el volteo, la paleta y las posiciones X e Y de 16 bits. Las posiciones indexadas se escriben entre comillas para que la coma de &amp;lt;code&amp;gt;,x&amp;lt;/code&amp;gt; no sea interpretada como un separador de parámetros de la macro.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt; finaliza la rutina mediante &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;, por lo que no se coloca otro &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; después de la llamada en este ejemplo.&lt;br /&gt;
&lt;br /&gt;
En el ejemplo, &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; indica que la pose no se voltea y &amp;lt;code&amp;gt;#$04&amp;lt;/code&amp;gt; selecciona la paleta A. Estos argumentos también pueden utilizar tablas o variables cuando el sprite necesite cambiar su orientación o paleta.&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!PoseIDMyStaticSprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo durante la instalación y queda disponible en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: se eliminan espacios, guiones bajos, guiones y otros separadores, y se escribe en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
Para obtener más información sobre la declaración de poses estáticas, consulta [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos de Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
== Instalar y probar el sprite ==&lt;br /&gt;
&lt;br /&gt;
Cada vez que se modifique alguno de los recursos procesados por Dynamic Xtreme, se debe reinstalar primero Dynamic Xtreme y después volver a insertar los sprites con PIXI. Esto incluye cambios en archivos &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt;, gráficos &amp;lt;code&amp;gt;*.bin&amp;lt;/code&amp;gt;, efectos &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y cualquier otro recurso dinámico utilizado por el sprite.&lt;br /&gt;
&lt;br /&gt;
El orden es importante: Dynamic Xtreme debe procesar primero los recursos y regenerar sus datos y defines; después PIXI puede ensamblar el sprite utilizando la información actualizada.&lt;br /&gt;
&lt;br /&gt;
Si añades, eliminas o modificas los includes de recursos &amp;lt;code&amp;gt;;#incdyn&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;;#incdri&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;;#incpale&amp;lt;/code&amp;gt; dentro del ASM, también debes reinstalar primero Dynamic Xtreme y después PIXI.&lt;br /&gt;
&lt;br /&gt;
Si solo modificas el código &amp;lt;code&amp;gt;*.asm&amp;lt;/code&amp;gt; del sprite, sin cambiar esos includes, no es necesario reinstalar Dynamic Xtreme. En ese caso basta con ejecutar PIXI nuevamente.&lt;br /&gt;
&lt;br /&gt;
Para conocer el proceso completo de instalación, configuración y reinstalación de recursos, consulta la [[Dynamic_Xtreme_Quick_Start|guía de inicio rápido de Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
Después de cada instalación, prueba el sprite en el juego y comprueba que sus poses, paletas, volteos y desplazamientos se muestren correctamente durante sus diferentes estados y animaciones.&lt;br /&gt;
&lt;br /&gt;
== Errores comunes ==&lt;br /&gt;
&lt;br /&gt;
=== Utilizar un nombre sin normalizar en un define generado ===&lt;br /&gt;
&lt;br /&gt;
Los nombres incluidos en los defines generados por Dynamic Xtreme deben escribirse con la normalización utilizada por la herramienta. Los espacios, guiones bajos y guiones se eliminan, y la primera letra de cada palabra se escribe en mayúscula siguiendo el estilo PascalCase.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, una pose llamada &amp;lt;code&amp;gt;my_sprite-pose&amp;lt;/code&amp;gt; utiliza el componente normalizado &amp;lt;code&amp;gt;MySpritePose&amp;lt;/code&amp;gt; dentro de un define como el siguiente:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!DynamicPoseIDMySpritePose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Escribir el nombre original con sus separadores, utilizar una combinación distinta de mayúsculas o confundir un define &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; con un &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt; hará que Asar no encuentre el símbolo. Ante una duda, revisa el nombre exacto generado en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Inicializar incorrectamente las variables del sprite ===&lt;br /&gt;
&lt;br /&gt;
Las variables utilizadas por Dynamic Xtreme deben recibir valores válidos cada vez que se crea un sprite. Cuando se utiliza &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt; deben comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, mientras que variables como &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LocalFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt; normalmente comienzan en 0. También deben configurarse las distancias utilizadas por &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Si estas tablas no se inicializan correctamente, el sprite puede reutilizar una paleta, una pose o información dejada por otro sprite que ocupó anteriormente el mismo slot. En cluster sprites y extended sprites, esta inicialización debe realizarse mediante la rutina de inicio simulada explicada anteriormente.&lt;br /&gt;
&lt;br /&gt;
=== No reservar un Extra Byte para la paleta ===&lt;br /&gt;
&lt;br /&gt;
Un sprite normal que utilice carga de paletas debe tener disponible al menos un Extra Byte en su archivo &amp;lt;code&amp;gt;*.cfg&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;*.json&amp;lt;/code&amp;gt;. Dynamic Xtreme utiliza &amp;lt;code&amp;gt;Extra Byte 1&amp;lt;/code&amp;gt; como &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; y, normalmente, también aprovecha sus cuatro bits bajos para seleccionar &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Si el sprite no declara ningún Extra Byte, &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt; no contendrá la configuración necesaria para seleccionar correctamente la paleta y la versión del sprite.&lt;br /&gt;
&lt;br /&gt;
=== No restaurar una paleta fija en la short routine ===&lt;br /&gt;
&lt;br /&gt;
Un sprite puede utilizar una paleta fija que ya se encuentre cargada en el nivel en lugar de llamar a &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;. En este caso todavía es necesario asignar manualmente a &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; el valor de la paleta que utilizará el dibujo.&lt;br /&gt;
&lt;br /&gt;
Los valores avanzan de dos en dos y corresponden a las paletas de sprites 8-F:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;: paleta 8.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;: paleta 9.&lt;br /&gt;
* &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt;: paleta A.&lt;br /&gt;
* &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt;: paleta B.&lt;br /&gt;
* &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt;: paleta C.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;: paleta D.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt;: paleta E.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt;: paleta F.&lt;br /&gt;
&lt;br /&gt;
El valor debe asignarse durante el &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; y también dentro de la short routine. Cuando &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; envía el sprite a la short routine, invalida &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;; por eso la paleta fija debe restaurarse en esa ruta:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
; Dentro de INIT&lt;br /&gt;
    LDA #$04            ; Paleta A&lt;br /&gt;
    STA !Palette,x&lt;br /&gt;
&lt;br /&gt;
; Dentro de SpriteCode&lt;br /&gt;
.ShortRoutine&lt;br /&gt;
    LDA #$04            ; Paleta A&lt;br /&gt;
    STA !Palette,x&lt;br /&gt;
&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    %SubOffScreen()&lt;br /&gt;
    ; Aquí va la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esta asignación manual solamente corresponde a sprites que utilizan una paleta fija y no llaman a &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;. Los sprites con carga dinámica deben conservar el flujo de asignación explicado en la sección de manejo de paletas.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_sprite_creation_guide&amp;diff=21381</id>
		<title>es/Dynamic Xtreme sprite creation guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_sprite_creation_guide&amp;diff=21381"/>
		<updated>2026-10-25T17:14:03Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# Revisión de Dynamic_Xtreme_dynamic_sprite_creation_guide.wiki&lt;br /&gt;
&lt;br /&gt;
Fecha: 24 de octubre de 2026. Fuente: `docs/SNESLab/es/Dynamic_Xtreme_dynamic_sprite_creation_guide.wiki`.&lt;br /&gt;
&lt;br /&gt;
Perspectiva de una primera lectura, sin conocimiento previo del proyecto. Se evalúan explicaciones y coherencia de los fragmentos publicados; no se analizaron archivos ASM ni se ensamblaron ejemplos. Alta: puede bloquear el tutorial o inducir una aplicación incorrecta; media: exige deducciones; baja: presentación.&lt;br /&gt;
&lt;br /&gt;
## Qué entendí&lt;br /&gt;
&lt;br /&gt;
El sprite prepara su estado, comprueba si debe renderizarse, obtiene paleta y pose y después dibuja la última pose disponible. Entendí por qué no se debe dibujar directamente la pose solicitada si todavía no está disponible. La descripción de las variables iniciales y de los estados inválidos ayuda a seguir ese proceso.&lt;br /&gt;
&lt;br /&gt;
## Observaciones y recomendaciones&lt;br /&gt;
&lt;br /&gt;
### 1. El ejemplo contradice la explicación sobre el fallo de recursos — Alta&lt;br /&gt;
&lt;br /&gt;
**Dónde:** SpriteCode, líneas 223–237, y explicación de la long routine, línea 252.&lt;br /&gt;
&lt;br /&gt;
**Evidencia:** los dos fallos usan `BCC ..Return`; el texto dice que «el ejemplo salta a .ShortRoutine» y que la lógica continúa. En el fragmento, la lógica está antes del retorno y se omite al tomar esos saltos.&lt;br /&gt;
&lt;br /&gt;
**Duda:** «¿El sprite debe detener su movimiento cuando falta una paleta o pose? ¿Qué flujo debo copiar?». La discrepancia es visible en el propio artículo, sin necesitar conocer las rutinas internas.&lt;br /&gt;
&lt;br /&gt;
**Recomendación:** hacer que explicación y ejemplo describan un único recorrido, indicando dónde se ejecuta la lógica en éxito y en fallo. Una pequeña tabla de los tres casos —fuera del área, recursos disponibles y recursos no disponibles— permitiría revisarlo. Validar después el ejemplo real antes de publicarlo.&lt;br /&gt;
&lt;br /&gt;
**Resolución:** aplicada al texto, conservando el ejemplo. El autor confirmó que, si falla la solicitud de paleta o pose, se debe retornar, sin pasar por la short routine. Se corrigió la explicación para indicar que los saltos a `..Return` terminan la rutina y omiten tanto el dibujo como la lógica posterior durante ese frame.&lt;br /&gt;
&lt;br /&gt;
### 2. El proceso completo prometido no incluye un recurso completo — Alta&lt;br /&gt;
&lt;br /&gt;
**Dónde:** introducción, archivos y resto de la guía.&lt;br /&gt;
&lt;br /&gt;
**Duda:** «¿Dónde preparo los gráficos? ¿Qué escribo exactamente en MySprite.dynamicinfo y MySprite.drawinfo? ¿Cómo conecto SpriteCode con MAIN?». Hay un árbol de archivos y rutinas aisladas, pero no una secuencia completa de creación de esos archivos ni un sprite mínimo terminado.&lt;br /&gt;
&lt;br /&gt;
**Recomendación:** comenzar con una pose de un tile y una paleta, mostrar todos los archivos necesarios y la configuración de PIXI, y terminar con su inserción y resultado. Enlazar formatos para ampliar el ejemplo, sin delegar allí los pasos mínimos del tutorial. Separar luego cluster, extended, efectos locales y dibujo estático como variantes.&lt;br /&gt;
&lt;br /&gt;
**Resolución:** descartada. El autor indica que habrá numerosos recursos completos disponibles en snestorage.dev, por lo que no se añadirá un sprite mínimo completo con todos sus archivos a esta guía.&lt;br /&gt;
&lt;br /&gt;
### 3. La configuración requerida en PIXI aparece demasiado tarde — Alta&lt;br /&gt;
&lt;br /&gt;
**Dónde:** INIT y opciones de paleta, líneas 78–208; «No reservar un Extra Byte», línea 546.&lt;br /&gt;
&lt;br /&gt;
**Duda:** «El INIT lee ExtraByte1 y el extra bit: ¿qué debo declarar en el JSON y qué escribo en Lunar Magic?». El requisito del Extra Byte se presenta como error común al final, después de utilizarlo en los ejemplos.&lt;br /&gt;
&lt;br /&gt;
**Recomendación:** mover la configuración necesaria antes del INIT. Mostrar una combinación de versión, modo y paleta con su byte hexadecimal resultante y dónde introducirlo. Explicar qué ocurre si una versión selecciona una entrada que no existe en la lista de paletas.&lt;br /&gt;
&lt;br /&gt;
**Resolución:** aplicada en la sección de carga de paletas, según lo indicado por el autor. Se añadió el requisito de configurar al menos un Extra Byte en el CFG/JSON de un sprite normal para utilizar la asignación de paletas. Se explicó el uso de Extra Byte 1 para `PaletteOption` y `Version`, y de los bits 5 y 4 de Extra Property Byte 2 para `PaletteAssignmentOption`, con los tres modos y sus valores. Se conservó la advertencia de errores comunes. No se añadió un tutorial de configuración de PIXI ni Lunar Magic.&lt;br /&gt;
&lt;br /&gt;
### 4. El orden de aprendizaje introduce símbolos antes de enseñar de dónde salen — Media&lt;br /&gt;
&lt;br /&gt;
**Dónde:** RenderBox y manejo de paletas/poses.&lt;br /&gt;
&lt;br /&gt;
**Duda:** «Todavía no he definido las poses, pero ya debo usar sus distancias e IDs generados. ¿En qué momento existen estos nombres?». Se repite muchas veces la normalización del nombre, pero falta un ejemplo que conecte nombre de archivo, nombre de pose y símbolo final.&lt;br /&gt;
&lt;br /&gt;
**Recomendación:** preparar primero los archivos y ejecutar la generación. Después presentar una tabla única con cada símbolo del tutorial y su origen exacto. Mantener la advertencia de consultar DXDefines, pero reducir la repetición de PascalCase en cada sección.&lt;br /&gt;
&lt;br /&gt;
**Resolución:** aplicada parcialmente según el acuerdo con el autor. No existía una tabla de origen de los defines en la guía, por lo que se añadió después de la explicación de los archivos y antes de la estructura del sprite. Resume los defines de distancias, tabla de paletas, poses dinámicas, poses de dibujo y efectos, con su origen y uso. Se conservaron las aclaraciones repetidas sobre origen, normalización y consulta de `DXDefines.asm` junto a cada uso: el autor considera que ayudan a evitar errores frecuentes sin obligar al lector a recordar otra sección. No se reorganizó el proceso de aprendizaje.&lt;br /&gt;
&lt;br /&gt;
### 5. Los fragmentos requieren un contrato común de registros y retorno — Alta&lt;br /&gt;
&lt;br /&gt;
**Dónde:** INIT, PaletteManagement y concatenación, líneas 82–112 y 303–348.&lt;br /&gt;
&lt;br /&gt;
**Duda:** «¿En qué tamaño entran A, X e Y? Después de copiar la paleta a X, ¿cómo recupera la siguiente rutina el índice del sprite? ¿Qué banco permite leer PaletteEffects?». La guía explica conservar Y, pero no ofrece un contrato igualmente explícito para X, DBR y el estado de salida de todas las llamadas.&lt;br /&gt;
&lt;br /&gt;
**Recomendación:** anteponer requisitos comunes y anotar los cambios especiales junto a cada ejemplo. Explicar qué llamadas recuperan el índice desde el contexto de PIXI y cuáles requieren que el llamador lo prepare. No afirmar que existe un fallo de implementación: la carencia comprobada es que el lector no puede deducir el contrato completo del tutorial.&lt;br /&gt;
&lt;br /&gt;
**Resolución:** aplicada mediante referencias a la API, según la propuesta del autor. Se añadió una referencia general para dudas sobre registros, parámetros y resultados, y enlaces directos desde los apartados correspondientes a RenderBox, asignación de paletas, concatenación de efectos, carga de poses y dibujo. No se añadió una sección de contratos de registros a la guía ni se modificaron los ejemplos en este punto.&lt;br /&gt;
&lt;br /&gt;
### 6. La regla «solo cambió el ASM» omite los comentarios de inclusión — Alta&lt;br /&gt;
&lt;br /&gt;
**Dónde:** «Instalar y probar el sprite», línea 520.&lt;br /&gt;
&lt;br /&gt;
**Duda:** «Si añado un ;#incdyn al ASM, ¿basta ejecutar PIXI?». La misma guía enseña que esos comentarios permiten que Dynamic Xtreme descubra recursos.&lt;br /&gt;
&lt;br /&gt;
**Recomendación:** limitar la excepción a cambios de lógica que no alteren declaraciones o selección de recursos. Enumerar como cambios que requieren regeneración los includes especiales y las listas utilizadas para descubrirlos. Unificar la regla con el Quick Start.&lt;br /&gt;
&lt;br /&gt;
**Resolución:** aplicada en ambos artículos por indicación del autor. La guía de sprites y Quick Start ahora indican que añadir, eliminar o modificar `;#incdyn`, `;#incdri` o `;#incpale` requiere reinstalar Dynamic Xtreme y después las herramientas consumidoras. Se aclaró que modificar solo el código ASM evita la reinstalación de Dynamic Xtreme únicamente si no se alteran esos includes.&lt;br /&gt;
&lt;br /&gt;
### 7. Sumar una paleta no especifica qué sucede en el extremo del rango — Media&lt;br /&gt;
&lt;br /&gt;
**Dónde:** PaletteAssignmentOption, línea 206: sumar `$10` para seleccionar la paleta siguiente.&lt;br /&gt;
&lt;br /&gt;
**Duda:** «¿Qué hago si el sprite principal ya usa la F? ¿Podría cambiar el bit del efecto al sumar?». No se indica condición de validez ni destino alternativo.&lt;br /&gt;
&lt;br /&gt;
**Recomendación:** declarar el rango en que se permite avanzar y el comportamiento que debe elegir el autor al alcanzar la última paleta. Añadir un ejemplo dentro del rango y otro que requiera una elección explícita, sin suponer que existe un retorno automático al principio.&lt;br /&gt;
&lt;br /&gt;
**Resolución:** aplicada con la restricción indicada por el autor. Cuando el sprite generado utiliza una paleta distinta seleccionada sumando `$10`, y el principal emplea asignación manual o manual sin carga, el sprite principal no puede utilizar la paleta F. Se indicó que debe configurarse entre la 8 y la E. No se propuso un retorno automático al comienzo del rango ni una selección alternativa en tiempo de ejecución. La review de esta guía queda completada.&lt;br /&gt;
&lt;br /&gt;
## Primer cambio recomendado&lt;br /&gt;
&lt;br /&gt;
Resolver la contradicción del flujo y construir un ejemplo mínimo completo. Son mejoras previas a ampliar los casos avanzados.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_files_and_formats&amp;diff=21380</id>
		<title>es/Dynamic Xtreme files and formats</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_files_and_formats&amp;diff=21380"/>
		<updated>2026-10-25T16:41:36Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_files_and_formats}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme utiliza un sistema de archivos propio y bien estructurado que permite al usuario tener un control preciso y flexible sobre los recursos, efectos y datos que se usan durante la ejecución del juego.&lt;br /&gt;
&lt;br /&gt;
Esta página documenta los diferentes tipos de archivos que maneja la herramienta, cómo funcionan, su propósito y los formatos específicos que utilizan (tanto los actuales como los legacy). Entender esta estructura es fundamental para aprovechar al máximo las capacidades de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Muchos de los formatos legacy presentes en Dynamic Xtreme provienen originalmente de Dynamic X, la versión antigua sobre la cual evolucionó el proyecto. Estos formatos continúan siendo totalmente compatibles con el objetivo de mantener soporte para una gran cantidad de recursos ya existentes desarrollados para Dynamic X.&lt;br /&gt;
&lt;br /&gt;
A continuación se detallan los principales tipos de archivos y sus formatos:&lt;br /&gt;
&lt;br /&gt;
== Tipos de Archivos ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme utiliza varios tipos de archivos especializados. A continuación se describen los principales:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Recursos Dinámicos&#039;&#039;&#039;: Son recursos que se guardan en el ROM de forma descomprimida. Normalmente se usan para sprites dinámicos, cambios de gráficos, cambios de tilemaps o cambios de paletas.&lt;br /&gt;
* &#039;&#039;&#039;Palette Effects (*.paleffect):&#039;&#039;&#039; Son archivos utilizados para registrar efectos de paletas de colores.&lt;br /&gt;
* &#039;&#039;&#039;Dynamic Info (*.dynamicinfo):&#039;&#039;&#039; Son archivos que se usan para incluir recursos dinámicos en el ROM y también generar la data relevante para los sprites dinámicos.&lt;br /&gt;
* &#039;&#039;&#039;Draw Info (*.drawinfo):&#039;&#039;&#039; Son archivos utilizados para generar las poses (cuadros de animación) para los sprites y luego poder dibujarlas en pantalla.&lt;br /&gt;
&lt;br /&gt;
== Inclusión de archivos desde PIXI y UberASMTool ==&lt;br /&gt;
&lt;br /&gt;
Los recursos de PIXI y UberASMTool pueden declarar los archivos que&lt;br /&gt;
utilizan mediante comentarios especiales dentro de su ASM principal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn  &amp;quot;ruta/al/recurso.dynamicinfo&amp;quot;&lt;br /&gt;
;#incdri  &amp;quot;ruta/al/recurso.drawinfo&amp;quot;&lt;br /&gt;
;#incpale &amp;quot;ruta/al/recurso.paleffect&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cada directiva registra un tipo de archivo diferente:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;;#incdyn&amp;lt;/code&amp;gt; incluye un archivo &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;;#incdri&amp;lt;/code&amp;gt; incluye un archivo &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;;#incpale&amp;lt;/code&amp;gt; incluye un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Las rutas son relativas al ASM principal que contiene la directiva.&lt;br /&gt;
Los archivos incluidos pueden encontrarse en la misma carpeta o en&lt;br /&gt;
cualquiera de sus subcarpetas.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme busca estas directivas únicamente en los ASM&lt;br /&gt;
principales registrados en las listas de PIXI y UberASMTool. No sigue&lt;br /&gt;
archivos cargados mediante &amp;lt;code&amp;gt;incsrc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los recursos internos de un &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt; o&lt;br /&gt;
&amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; incluido de esta forma utilizan como base la&lt;br /&gt;
carpeta donde se encuentra su archivo de definición.&lt;br /&gt;
&lt;br /&gt;
== Recursos Dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Los Recursos Dinámicos son uno de los sistemas centrales de Dynamic Xtreme. Estos recursos se almacenan en el ROM de forma descomprimida, lo que permite cargarlos y utilizarlos rápidamente durante la ejecución del juego.&lt;br /&gt;
&lt;br /&gt;
=== ¿Cómo funciona el sistema? ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme recopila todos los recursos dinámicos, los organiza en paquetes de máximo 1 bank (32 O 64 KB) y los inserta automáticamente en el ROM. Si el ROM tiene hi-banks disponibles, el tool prioriza estos bancos para la inserción, mejorando la organización del espacio.&lt;br /&gt;
&lt;br /&gt;
No existe una limitación estricta sobre el tipo de datos que se pueden insertar, aunque la mayoría de los archivos suelen ser de tipo &#039;&#039;&#039;&amp;quot;*.bin&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Usos principales ===&lt;br /&gt;
&lt;br /&gt;
Los recursos dinámicos se utilizan comúnmente para:&lt;br /&gt;
* &#039;&#039;&#039;Gráficos:&#039;&#039;&#039; Gráficos de sprites dinámicos o reemplazos gráficos en tiempo real.&lt;br /&gt;
* &#039;&#039;&#039;Tilemaps:&#039;&#039;&#039; Reemplazar tiles de los diferentes layers del nivel.&lt;br /&gt;
* &#039;&#039;&#039;Paletas de colores:&#039;&#039;&#039; Reemplazar paletas completas o asignar paletas específicas a sprites dinámicos.&lt;br /&gt;
* &#039;&#039;&#039;Otros&#039;&#039;&#039;: Cualquier tipo de información que se desee almacenar en el ROM, como muestras de audio .brr, tablas de datos, etc.&lt;br /&gt;
&lt;br /&gt;
Esto hace que el sistema sea extremadamente flexible, permitiendo no solo usos gráficos sino también cualquier otro tipo de dato que el usuario necesite tener disponible en el ROM de forma rápida.&lt;br /&gt;
&lt;br /&gt;
=== Archivos de Paletas de colores ===&lt;br /&gt;
&lt;br /&gt;
Actualmente, la mejor forma de guardar archivos de paletas de colores es utilizando archivos binarios (&#039;&#039;&#039;*.bin&#039;&#039;&#039;) donde cada color ocupa 2 bytes siguiendo el formato de color utilizado por el SNES. Existen herramientas que facilitan este proceso, como [https://www.smwcentral.net/?p=section&amp;amp;a=details&amp;amp;id=24827 Pal2Bin].&lt;br /&gt;
&lt;br /&gt;
Para entender esto, es importante considerar que el formato de color del SNES es BGR555. Esto significa que cada color se almacena utilizando 5 bits para azul, 5 bits para verde y 5 bits para rojo.&lt;br /&gt;
&lt;br /&gt;
Conceptualmente, los bits se organizan así:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;-BBBBB GGGGG RRRRR&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sin embargo, debido al endian utilizado por el SNES, los bytes deben almacenarse invertidos en memoria, por lo que internamente terminan organizados así:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GGG RRRRR -BBBBB GG&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Debido a que este formato puede resultar confuso para usuarios no familiarizados con hardware del SNES, a futuro se planea incorporar soporte mejorado para archivos &#039;&#039;&#039;*.pal&#039;&#039;&#039;, los cuales son mucho más conocidos y utilizados en herramientas gráficas modernas.&lt;br /&gt;
&lt;br /&gt;
En el caso de las paletas utilizadas por sprites dinámicos, estas deben contener un máximo de 15 colores. Esto significa que únicamente deben incluirse los colores 1 al 15 de la paleta correspondiente, ya que el color 0 es utilizado como transparencia.&lt;br /&gt;
&lt;br /&gt;
=== Gráficos para sprites dinámicos ===&lt;br /&gt;
&lt;br /&gt;
Los gráficos de un sprite dinámico se dividen en poses. Cada pose contiene&lt;br /&gt;
los tiles que deben cargarse en VRAM para mostrar un cuadro de animación.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme admite dos formas de organizar estos gráficos:&lt;br /&gt;
&lt;br /&gt;
* El &#039;&#039;&#039;formato actual&#039;&#039;&#039;, recomendado para recursos nuevos.&lt;br /&gt;
* El &#039;&#039;&#039;formato legacy&#039;&#039;&#039;, conservado para mantener compatibilidad con&lt;br /&gt;
recursos creados para Dynamic X.&lt;br /&gt;
&lt;br /&gt;
Ambos formatos producen el mismo resultado dentro del juego. La diferencia&lt;br /&gt;
se encuentra únicamente en cómo deben organizarse los gráficos dentro del&lt;br /&gt;
archivo.&lt;br /&gt;
&lt;br /&gt;
==== Formato actual ====&lt;br /&gt;
&lt;br /&gt;
En el formato actual, los gráficos se organizan utilizando espacios de&lt;br /&gt;
16x16 píxeles.&lt;br /&gt;
&lt;br /&gt;
Los tiles de cada pose se colocan de forma consecutiva. Después de los&lt;br /&gt;
gráficos de una pose comienzan los gráficos de la siguiente.&lt;br /&gt;
&lt;br /&gt;
El autor decide el orden de los tiles de cada pose en el archivo de gráficos. El DynamicInfo indica cuántos tiles pertenecen a cada pose, y el DrawInfo indica dónde se dibuja cada uno. Ambos deben corresponder con la organización de los gráficos.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, una pose de 32x32 píxeles normalmente utiliza cuatro tiles de&lt;br /&gt;
16x16:&lt;br /&gt;
&lt;br /&gt;
[[File:imagen 2026-05-17 221817296.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
La cantidad de tiles utilizada por cada pose se declara dentro del archivo&lt;br /&gt;
&amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt; mediante&lt;br /&gt;
&amp;lt;code&amp;gt;NumberOf16x16TilesPerPose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme reorganiza automáticamente estos gráficos al formato interno&lt;br /&gt;
utilizado para realizar las transferencias DMA. Por esta razón, el autor del&lt;br /&gt;
recurso no necesita preparar manualmente el layout utilizado en VRAM.&lt;br /&gt;
&lt;br /&gt;
Este es el formato recomendado para crear recursos nuevos.&lt;br /&gt;
&lt;br /&gt;
Si el último tile de 16×16 solo se utiliza parcialmente, puedes indicar qué partes conservar mediante &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;q3&amp;lt;/code&amp;gt;. Los gráficos se preparan con el espacio completo de 16×16; Dynamic Xtreme conserva las partes indicadas y descarta las restantes al procesar el recurso.&lt;br /&gt;
&lt;br /&gt;
Cada celda de las siguientes tablas representa un tile de 8×8. La tabla completa representa el último tile de 16×16 de la pose. El verde indica las partes utilizadas y el gris las que se descartan.&lt;br /&gt;
&lt;br /&gt;
===== q =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! !! Mitad izquierda !! Mitad derecha&lt;br /&gt;
|-&lt;br /&gt;
! Mitad superior&lt;br /&gt;
| style=&amp;quot;background-color:#d5f5dc; color:#202122;&amp;quot; | Tile de 8×8 superior izquierdo: usado&lt;br /&gt;
| style=&amp;quot;background-color:#eaecf0; color:#202122;&amp;quot; | Tile de 8×8 superior derecho: no utilizado&lt;br /&gt;
|-&lt;br /&gt;
! Mitad inferior&lt;br /&gt;
| style=&amp;quot;background-color:#eaecf0; color:#202122;&amp;quot; | Tile de 8×8 inferior izquierdo: no utilizado&lt;br /&gt;
| style=&amp;quot;background-color:#eaecf0; color:#202122;&amp;quot; | Tile de 8×8 inferior derecho: no utilizado&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== h =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! !! Mitad izquierda !! Mitad derecha&lt;br /&gt;
|-&lt;br /&gt;
! Mitad superior&lt;br /&gt;
| style=&amp;quot;background-color:#d5f5dc; color:#202122;&amp;quot; | Tile de 8×8 superior izquierdo: usado&lt;br /&gt;
| style=&amp;quot;background-color:#d5f5dc; color:#202122;&amp;quot; | Tile de 8×8 superior derecho: usado&lt;br /&gt;
|-&lt;br /&gt;
! Mitad inferior&lt;br /&gt;
| style=&amp;quot;background-color:#eaecf0; color:#202122;&amp;quot; | Tile de 8×8 inferior izquierdo: no utilizado&lt;br /&gt;
| style=&amp;quot;background-color:#eaecf0; color:#202122;&amp;quot; | Tile de 8×8 inferior derecho: no utilizado&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== q3 =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! !! Mitad izquierda !! Mitad derecha&lt;br /&gt;
|-&lt;br /&gt;
! Mitad superior&lt;br /&gt;
| style=&amp;quot;background-color:#d5f5dc; color:#202122;&amp;quot; | Tile de 8×8 superior izquierdo: usado&lt;br /&gt;
| style=&amp;quot;background-color:#d5f5dc; color:#202122;&amp;quot; | Tile de 8×8 superior derecho: usado&lt;br /&gt;
|-&lt;br /&gt;
! Mitad inferior&lt;br /&gt;
| style=&amp;quot;background-color:#d5f5dc; color:#202122;&amp;quot; | Tile de 8×8 inferior izquierdo: usado&lt;br /&gt;
| style=&amp;quot;background-color:#eaecf0; color:#202122;&amp;quot; | Tile de 8×8 inferior derecho: no utilizado&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Formato legacy ====&lt;br /&gt;
&lt;br /&gt;
El formato legacy requiere que los gráficos ya se encuentren organizados&lt;br /&gt;
según los bloques que serán transferidos mediante DMA.&lt;br /&gt;
&lt;br /&gt;
Para una pose que utiliza siete tiles de 16x16 o menos, cada tile debe&lt;br /&gt;
separarse en dos mitades de 16x8. Primero se almacenan todas las mitades&lt;br /&gt;
superiores y después todas las mitades inferiores.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, una pose formada por cuatro tiles:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;t1 t2 t3 t4&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
debe almacenarse de esta manera:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;t1th t2th t3th t4th t1bh t2bh t3bh t4bh&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Donde:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;th&amp;lt;/code&amp;gt; representa la mitad superior del tile.&lt;br /&gt;
* &amp;lt;code&amp;gt;bh&amp;lt;/code&amp;gt; representa la mitad inferior del tile.&lt;br /&gt;
&lt;br /&gt;
Cuando una pose contiene ocho tiles de 16x16 o más, cada fila completa de&lt;br /&gt;
ocho tiles puede almacenarse directamente. Los tiles restantes se organizan&lt;br /&gt;
utilizando el sistema de mitades explicado anteriormente.&lt;br /&gt;
&lt;br /&gt;
La distribución de cada pose se declara mediante&lt;br /&gt;
&amp;lt;code&amp;gt;PosesChunksSizes&amp;lt;/code&amp;gt; dentro del archivo&lt;br /&gt;
&amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Este formato ofrece control directo sobre la organización interna, pero es&lt;br /&gt;
más difícil de preparar y mantener. Se recomienda principalmente para&lt;br /&gt;
recursos antiguos o casos avanzados.&lt;br /&gt;
&lt;br /&gt;
== Efectos de Paletas ==&lt;br /&gt;
&lt;br /&gt;
Los archivos de Efectos de paletas se almacenan dentro de la carpeta PaletteEffects y utilizan la extensión &#039;&#039;&#039;&amp;quot;*.paleffect&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Los efectos de paleta permiten realizar modificaciones de colores en tiempo real sobre las paletas utilizadas por el juego. Estos efectos pueden ser utilizados por el sistema global de efectos de paleta de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
El efecto global afecta a todos los colores de cada paleta habilitada para recibirlo. Del mismo modo, un efecto aplicado a un sprite completo afecta a toda la paleta del sprite. Estos sistemas no permiten seleccionar colores individuales dentro de una paleta.&lt;br /&gt;
&lt;br /&gt;
Si necesitas aplicar un efecto solo a colores específicos, debes hacerlo manualmente mediante las macros y rutinas descritas en la [[es/Dynamic_Xtreme_ASM_API|API ASM de Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
Internamente, estos sistemas funcionan modificando los canales &#039;&#039;&#039;RGB&#039;&#039;&#039; o &#039;&#039;&#039;HSL&#039;&#039;&#039; de los colores de la paleta para producir distintos efectos visuales.&lt;br /&gt;
&lt;br /&gt;
Algunos usos comunes incluyen:&lt;br /&gt;
&lt;br /&gt;
* Transiciones de día a noche.&lt;br /&gt;
* Flashes rojos para indicar peligro.&lt;br /&gt;
* Efectos cyan intermitentes para objetos a punto de explotar.&lt;br /&gt;
* Cambios de tinte para efectos tipo discoteca.&lt;br /&gt;
* Transiciones suaves entre estados visuales.&lt;br /&gt;
* Efectos de iluminación o ambientación.&lt;br /&gt;
&lt;br /&gt;
El sistema permite una gran cantidad de combinaciones y efectos distintos.&lt;br /&gt;
&lt;br /&gt;
=== Tipos de efectos ===&lt;br /&gt;
&lt;br /&gt;
Actualmente existen los siguientes efectos:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixRGB (ID 0)&#039;&#039;&#039;: Interpola los canales &#039;&#039;&#039;RGB&#039;&#039;&#039; con un color base.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixHSL (ID 1)&#039;&#039;&#039;: Interpola los canales &#039;&#039;&#039;HSL&#039;&#039;&#039; con un color base.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixRG (ID 2)&#039;&#039;&#039;: Interpola únicamente &#039;&#039;&#039;R&#039;&#039;&#039; y &#039;&#039;&#039;G&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixHS (ID 3)&#039;&#039;&#039;: Interpola únicamente &#039;&#039;&#039;H&#039;&#039;&#039; y &#039;&#039;&#039;S&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixRB (ID 4)&#039;&#039;&#039;: Interpola únicamente &#039;&#039;&#039;R&#039;&#039;&#039; y &#039;&#039;&#039;B&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixHL (ID 5)&#039;&#039;&#039;: Interpola únicamente &#039;&#039;&#039;H&#039;&#039;&#039; y &#039;&#039;&#039;L&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixGB (ID 6)&#039;&#039;&#039;: Interpola únicamente &#039;&#039;&#039;G&#039;&#039;&#039; y &#039;&#039;&#039;B&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixSL (ID 7)&#039;&#039;&#039;: Interpola únicamente &#039;&#039;&#039;S&#039;&#039;&#039; y &#039;&#039;&#039;L&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixR (ID 8)&#039;&#039;&#039;: Interpola únicamente el canal &#039;&#039;&#039;R&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixH (ID 9)&#039;&#039;&#039;: Interpola únicamente el canal &#039;&#039;&#039;H&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixG (ID 10)&#039;&#039;&#039;: Interpola únicamente el canal &#039;&#039;&#039;G&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixS (ID 11)&#039;&#039;&#039;: Interpola únicamente el canal &#039;&#039;&#039;S&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixB (ID 12)&#039;&#039;&#039;: Interpola únicamente el canal &#039;&#039;&#039;B&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;MixL (ID 13)&#039;&#039;&#039;: Interpola únicamente el canal &#039;&#039;&#039;L&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;PalTransitionRGB (ID 14)&#039;&#039;&#039;: Interpola una paleta completa hacia otra utilizando canales &#039;&#039;&#039;RGB&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;PalTransitionHSL (ID 15)&#039;&#039;&#039;: Interpola una paleta completa hacia otra utilizando canales &#039;&#039;&#039;HSL&#039;&#039;&#039;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;PalFunctionRGB (ID 16)&#039;&#039;&#039;: Aplica una transformación lineal sobre los canales &#039;&#039;&#039;RGB&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
* R = R11*R + R12*G + R13*B&lt;br /&gt;
* G = R21*R + R22*G + R23*B&lt;br /&gt;
* B = R31*R + R32*G + R33*B&lt;br /&gt;
&lt;br /&gt;
Donde:&lt;br /&gt;
&lt;br /&gt;
* RXY Son ratios&lt;br /&gt;
* R Corresponde al canal rojo&lt;br /&gt;
* G Corresponde al canal verde&lt;br /&gt;
* B Corresponde al canal azul&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota:&#039;&#039;&#039; Este efecto aún no se encuentra implementado.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;PalFunctionHSL (ID 17)&#039;&#039;&#039;: Aplica una transformación lineal sobre los canales &#039;&#039;&#039;HSL&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
* H = R11*H + R12*S + R13*L&lt;br /&gt;
* S = R21*H + R22*S + R23*L&lt;br /&gt;
* L = R31*H + R32*S + R33*L&lt;br /&gt;
&lt;br /&gt;
Donde:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RXY&#039;&#039;&#039; Son ratios.&lt;br /&gt;
* &#039;&#039;&#039;H&#039;&#039;&#039; Corresponde al tinte (&#039;&#039;&#039;Hue&#039;&#039;&#039;).&lt;br /&gt;
* &#039;&#039;&#039;S&#039;&#039;&#039; Corresponde a la saturación.&lt;br /&gt;
* &#039;&#039;&#039;L&#039;&#039;&#039; Corresponde al brillo (&#039;&#039;&#039;Lightness&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota:&#039;&#039;&#039; Este efecto aún no se encuentra implementado.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Formato de archivos ====&lt;br /&gt;
&lt;br /&gt;
Los efectos de paleta utilizan un formato basado en JSON:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: []&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Donde:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Effects&#039;&#039;&#039;: Contiene la lista de efectos utilizados.&lt;br /&gt;
&lt;br /&gt;
===== Formato simple =====&lt;br /&gt;
&lt;br /&gt;
El formato simple define un único efecto:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Channel1&amp;quot;: 31,&lt;br /&gt;
  &amp;quot;Channel2&amp;quot;: 0,&lt;br /&gt;
  &amp;quot;Channel3&amp;quot;: 0,&lt;br /&gt;
  &amp;quot;Ratio1&amp;quot;: 64,&lt;br /&gt;
  &amp;quot;Ratio2&amp;quot;: 64,&lt;br /&gt;
  &amp;quot;Ratio3&amp;quot;: 64,&lt;br /&gt;
  &amp;quot;EffectType&amp;quot;: 0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Donde:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;Channel1&#039;&#039;&#039;, &#039;&#039;&#039;Channel2&#039;&#039;&#039;, &#039;&#039;&#039;Channel3&#039;&#039;&#039; corresponden a los valores de canales principales&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;En efectos &#039;&#039;&#039;RGB&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;1 = R&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;2 = G&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;3 = B&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;En efectos &#039;&#039;&#039;HSL&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;1 = H&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;2 = S&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;3 = L&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;Ratio1&#039;&#039;&#039;, &#039;&#039;&#039;Ratio2&#039;&#039;&#039; y &#039;&#039;&#039;Ratio3&#039;&#039;&#039; son factores de interpolación: se utilizan para calcular cuánto influye el efecto en cada canal. Sus valores van de 0 (influencia mínima) a 127 (influencia máxima).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;EffectType&#039;&#039;&#039; corresponde al ID del efecto utilizado.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, el &amp;lt;code&amp;gt;MixRGB&amp;lt;/code&amp;gt; anterior mezcla los colores originales con rojo: &amp;lt;code&amp;gt;Channel1 = 31&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Channel2 = 0&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Channel3 = 0&amp;lt;/code&amp;gt;. Con los tres ratios en 64, el resultado queda aproximadamente a mitad de camino entre cada color original y ese rojo. Así, un color negro se convierte en un rojo de intensidad media. Al aumentar los ratios, el resultado se acerca más al rojo indicado.&lt;br /&gt;
&lt;br /&gt;
===== Transiciones de paleta =====&lt;br /&gt;
&lt;br /&gt;
Los efectos &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt; y&lt;br /&gt;
&amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt; permiten interpolar los colores de una&lt;br /&gt;
paleta hacia otra.&lt;br /&gt;
&lt;br /&gt;
A diferencia de los efectos de mezcla normales, estos efectos utilizan&lt;br /&gt;
el campo &amp;lt;code&amp;gt;Palette&amp;lt;/code&amp;gt; para indicar la paleta objetivo:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Palette&amp;quot;: &amp;quot;Palettes/NightPalette.bin&amp;quot;,&lt;br /&gt;
  &amp;quot;Ratio1&amp;quot;: 64,&lt;br /&gt;
  &amp;quot;Ratio2&amp;quot;: 64,&lt;br /&gt;
  &amp;quot;Ratio3&amp;quot;: 64,&lt;br /&gt;
  &amp;quot;EffectType&amp;quot;: 14&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo se utiliza &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;, cuyo ID es&lt;br /&gt;
&amp;lt;code&amp;gt;14&amp;lt;/code&amp;gt;. Para realizar la transición en HSL debe utilizarse&lt;br /&gt;
&amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt;, cuyo ID es &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El archivo indicado en &amp;lt;code&amp;gt;Palette&amp;lt;/code&amp;gt; debe contener colores&lt;br /&gt;
BGR555 de 2 bytes. Dynamic Xtreme convierte automáticamente la paleta&lt;br /&gt;
al formato interno requerido por el efecto RGB o HSL.&lt;br /&gt;
&lt;br /&gt;
Los valores &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y&lt;br /&gt;
&amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; controlan la interpolación de sus respectivos&lt;br /&gt;
canales y deben encontrarse entre 0 y 127.&lt;br /&gt;
&lt;br /&gt;
Cuando el archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; se encuentra en la carpeta&lt;br /&gt;
tradicional &amp;lt;code&amp;gt;PaletteEffects&amp;lt;/code&amp;gt;, la ruta de&lt;br /&gt;
&amp;lt;code&amp;gt;Palette&amp;lt;/code&amp;gt; se resuelve desde&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicResources&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cuando el efecto se incluye desde PIXI o UberASMTool mediante&lt;br /&gt;
&amp;lt;code&amp;gt;;#incpale&amp;lt;/code&amp;gt;, la ruta se resuelve desde la carpeta donde se&lt;br /&gt;
encuentra el archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Rangos de valores ====&lt;br /&gt;
&lt;br /&gt;
* Los valores de canales (&#039;&#039;&#039;Channel&#039;&#039;&#039;) utilizan rangos entre &#039;&#039;&#039;0&#039;&#039;&#039; y &#039;&#039;&#039;31&#039;&#039;&#039;.&lt;br /&gt;
* Los valores de ratios (&#039;&#039;&#039;Ratio&#039;&#039;&#039;) utilizan rangos entre &#039;&#039;&#039;0&#039;&#039;&#039; y &#039;&#039;&#039;127&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== DynamicInfo ==&lt;br /&gt;
&lt;br /&gt;
Los archivos &#039;&#039;&#039;DynamicInfo&#039;&#039;&#039; se almacenan dentro de la carpeta &#039;&#039;&#039;DynamicInfos&#039;&#039;&#039; y utilizan la extensión &#039;&#039;&#039;*.dynamicinfo&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Estos archivos tienen 2 funciones principales:&lt;br /&gt;
&lt;br /&gt;
* Incluir recursos dinámicos dentro del ROM.&lt;br /&gt;
* Definir qué gráficos corresponden a sprites dinámicos y cómo debe cargarse cada pose.&lt;br /&gt;
&lt;br /&gt;
La estructura básica de un archivo `DynamicInfo` es la siguiente:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PosesGraphics:&lt;br /&gt;
    MyGraphics.bin&lt;br /&gt;
    AnotherGraphics.bin&lt;br /&gt;
&lt;br /&gt;
Palettes:&lt;br /&gt;
    MyPal.bin&lt;br /&gt;
    AnotherPal.bin&lt;br /&gt;
&lt;br /&gt;
Resources:&lt;br /&gt;
    MyResource.bin&lt;br /&gt;
    AnotherResource.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Estas secciones funcionan como listas de recursos dinámicos que serán incluidos por Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
La base de las rutas depende de cómo se registre el archivo DynamicInfo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Método !! Desde dónde se buscan los archivos de PosesGraphics, Palettes y Resources&lt;br /&gt;
|-&lt;br /&gt;
| Carpetas tradicionales: DynamicInfo dentro de &amp;lt;code&amp;gt;DynamicInfos&amp;lt;/code&amp;gt;&lt;br /&gt;
| Las rutas son relativas a la carpeta &amp;lt;code&amp;gt;DynamicResources&amp;lt;/code&amp;gt;, junto al ejecutable de Dynamic Xtreme.&lt;br /&gt;
|-&lt;br /&gt;
| Inclusión mediante &amp;lt;code&amp;gt;;#incdyn&amp;lt;/code&amp;gt;&lt;br /&gt;
| Las rutas son relativas a la carpeta donde se encuentra el archivo &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt; incluido.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, en el método tradicional, &amp;lt;code&amp;gt;Graficos/MyGraphics.bin&amp;lt;/code&amp;gt; se busca en &amp;lt;code&amp;gt;DynamicResources/Graficos/MyGraphics.bin&amp;lt;/code&amp;gt;, no junto al DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PosesGraphics&#039;&#039;&#039; contiene archivos gráficos para sprites dinámicos. Estos deben utilizar formato &#039;&#039;&#039;*.bin&#039;&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;Palettes&#039;&#039;&#039; contiene archivos de paletas de colores. Actualmente utilizan formato &#039;&#039;&#039;*.bin&#039;&#039;&#039;, aunque a futuro se planea agregar soporte para archivos &#039;&#039;&#039;*.pal&#039;&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;Resources&#039;&#039;&#039; permite incluir recursos dinámicos arbitrarios y no posee restricciones específicas de formato.&lt;br /&gt;
&lt;br /&gt;
En el caso de PosesGraphics, cuando se utilizan múltiples archivos gráficos, todos ellos son combinados internamente en un único gran bloque de gráficos siguiendo el orden en el que fueron declarados.&lt;br /&gt;
&lt;br /&gt;
Posteriormente, cada pose es recortada desde esa data combinada y almacenada dentro del ROM de la forma más conveniente posible para el sistema dinámico.&lt;br /&gt;
&lt;br /&gt;
Debido a esto, no existe una diferencia práctica importante entre:&lt;br /&gt;
&lt;br /&gt;
* Utilizar un único archivo grande de gráficos.&lt;br /&gt;
* Utilizar múltiples archivos pequeños separados.&lt;br /&gt;
&lt;br /&gt;
Ambos enfoques producirán el mismo resultado interno dentro de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Además de estas listas de recursos, los archivos &#039;&#039;&#039;DynamicInfo&#039;&#039;&#039; también contienen la definición de las poses dinámicas utilizadas por el sprite.&lt;br /&gt;
&lt;br /&gt;
La forma en la que estas poses son definidas depende del formato utilizado por el recurso:&lt;br /&gt;
&lt;br /&gt;
* Formato actual (&#039;&#039;&#039;NumberOf16x16TilesPerPose&#039;&#039;&#039;).&lt;br /&gt;
* Formato legacy (&#039;&#039;&#039;PosesChunksSizes&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
=== Formato Actual ===&lt;br /&gt;
&lt;br /&gt;
El formato moderno fue diseñado para simplificar la creación y mantenimiento de sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
En este formato, el usuario únicamente necesita indicar cuántos tiles de 16x16 utiliza cada pose. Dynamic Xtreme se encarga automáticamente de procesar los gráficos y convertirlos internamente al formato optimizado utilizado por el sistema dinámico.&lt;br /&gt;
&lt;br /&gt;
Ejemplo:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
NumberOf16x16TilesPerPose:&lt;br /&gt;
.Pose0 5&lt;br /&gt;
.Pose1 7h&lt;br /&gt;
.Pose2..6 4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo:&lt;br /&gt;
&lt;br /&gt;
* Pose0 utiliza 5 tiles de 16x16.&lt;br /&gt;
* Pose1 utiliza 7 tiles de 16x16 y adicionalmente una mitad superior (16x8).&lt;br /&gt;
* Pose2 hasta Pose6 utilizan 4 tiles de 16x16.&lt;br /&gt;
&lt;br /&gt;
El formato también permite utilizar modificadores para representar tiles parciales:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;q&#039;&#039;&#039;: Tile 8x8 superior izquierdo.&lt;br /&gt;
* &#039;&#039;&#039;h&#039;&#039;&#039;: Mitad superior (16x8).&lt;br /&gt;
* &#039;&#039;&#039;q3&#039;&#039;&#039;: Mitad superior + tile inferior izquierdo (16x8 + 8x8).&lt;br /&gt;
&lt;br /&gt;
De este modo es posible incluir un tile de 16x16 que contenga gráficos de manera parcial. Estos tiles parciales no permiten todas las combinaciones posibles, debido a que muchas de ellas no son prácticas para el sistema. Únicamente se consideran las configuraciones más comunes y útiles.&lt;br /&gt;
&lt;br /&gt;
Internamente, Dynamic Xtreme transforma automáticamente este formato al formato legacy, ya que dicho formato se encuentra optimizado para realizar transferencias DMA hacia VRAM de manera más eficiente.&lt;br /&gt;
&lt;br /&gt;
=== Formato Legacy ===&lt;br /&gt;
&lt;br /&gt;
El formato legacy utiliza una tabla llamada PosesChunksSizes, la cual define manualmente cómo deben organizarse los gráficos dinámicos internamente.&lt;br /&gt;
&lt;br /&gt;
Ejemplo:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PosesChunksSizes:&lt;br /&gt;
Pose0_PoseChunksSizes:&lt;br /&gt;
    db $02,$02&lt;br /&gt;
Pose1_PoseChunksSizes:&lt;br /&gt;
    db $02,$02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cada pose posee una subtabla compuesta por 2 valores.&lt;br /&gt;
&lt;br /&gt;
La idea detrás de estos valores es representar cuántas rutinas DMA serían necesarias para transferir los gráficos de la pose hacia VRAM en condiciones ideales, es decir, asumiendo que el sprite se encuentra alineado al inicio de la sección de sprites de VRAM. En la práctica, en condiciones ideales se necesita 1 o 2 rutinas DMA.&lt;br /&gt;
&lt;br /&gt;
La mayoría de las veces, la primera rutina DMA transfiere una cantidad mayor de datos que la segunda.&lt;br /&gt;
&lt;br /&gt;
Cada uno de los 2 valores representa la cantidad de tiles de 8x8 transferidos por cada rutina DMA.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
db $02,$02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Significa:&lt;br /&gt;
&lt;br /&gt;
* la primera rutina DMA transfiere 2 tiles de 8x8&lt;br /&gt;
* la segunda rutina DMA transfiere otros 2 tiles de 8x8&lt;br /&gt;
&lt;br /&gt;
En casos especiales donde el sprite utiliza una cantidad de tiles de 16x16 que completa filas exactas dentro de VRAM (por ejemplo múltiplos de 8 tiles de 16x16), es posible realizar toda la transferencia utilizando una sola rutina DMA. En esos casos, el segundo valor se define como $00.&lt;br /&gt;
&lt;br /&gt;
Este formato fue reemplazado por el formato actual debido a que resultaba complejo y poco intuitivo para la mayoría de usuarios. Actualmente se recomienda utilizar NumberOf16x16TilesPerPose, aunque el legacy continúa siendo totalmente compatible y sigue ofreciendo mayor flexibilidad para casos avanzados.&lt;br /&gt;
&lt;br /&gt;
== DrawInfo ==&lt;br /&gt;
&lt;br /&gt;
Los archivos DrawInfo se almacenan dentro de la carpeta DrawInfos y utilizan la extensión &#039;&#039;&#039;&amp;quot;*.drawinfo&amp;quot;&#039;&#039;&#039; y contienen la información necesaria para dibujar poses en pantalla.&lt;br /&gt;
&lt;br /&gt;
Internamente, Dynamic Xtreme recopila esta información y genera rutinas gráficas optimizadas automáticamente. Cada rutina gráfica agrupa múltiples poses que comparten características similares y es optimizada específicamente para ese tipo de poses. Esto permite no solo un sistema global de renderizado de poses, sino también un sistema bastante eficiente en una gran cantidad de casos.&lt;br /&gt;
&lt;br /&gt;
Para comprender cómo funcionan los archivos DrawInfo, es necesario entender a grandes rasgos cómo funciona la OAM del SNES.&lt;br /&gt;
&lt;br /&gt;
La OAM es una memoria especial utilizada para almacenar información de sprites. En el caso del SMW, este trabaja utilizando tiles de 8x8 y 16x16.&lt;br /&gt;
&lt;br /&gt;
Cada tile posee los siguientes atributos:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;TileCode&#039;&#039;&#039;: a veces llamado simplemente Tile, corresponde a un ID interno utilizado por la consola para indicar qué gráfico específico de VRAM debe utilizarse.&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nota:&#039;&#039;&#039; Cuando se trabaja con sprites dinámicos, los TileCodes deben definirse asumiendo que el sprite fue cargado al inicio de la sección de sprites de VRAM. &lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
Dynamic Xtreme se encarga automáticamente de ajustar internamente estos valores dependiendo de la posición real donde la pose haya sido cargada en VRAM durante la ejecución.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;Properties&#039;&#039;&#039;: corresponde a un byte con propiedades especiales del tile. Este byte utiliza el siguiente formato:&lt;br /&gt;
* &#039;&#039;&#039;YXCCPPPT&#039;&#039;&#039;&lt;br /&gt;
Donde:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;Y&#039;&#039;&#039;: indica si el tile se encuentra flippeado verticalmente.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;X&#039;&#039;&#039;: indica si el tile se encuentra flippeado horizontalmente.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;CC&#039;&#039;&#039;: prioridad del tile respecto a los layers (mayor valor = mayor prioridad).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;PPP&#039;&#039;&#039;: paleta de sprites utilizada (000 =&amp;gt; palette 8, 001 =&amp;gt; palette 9, ..., 111 =&amp;gt; palette F).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;T&#039;&#039;&#039;: indica qué página gráfica utilizar (0 =&amp;gt; SP12, 1 =&amp;gt; SP34).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota:&#039;&#039;&#039; Es posible definir Properties generales para todos los tiles de una pose o sprite. Debido a esto, normalmente las properties más importantes dentro de los archivos DrawInfo son Y, X y T, mientras que las propiedades CC y PPP suelen configurarse desde el código que llama al sistema.&lt;br /&gt;
&lt;br /&gt;
En el caso específico de sprites dinámicos, la property T normalmente no necesita ser configurada manualmente, ya que Dynamic Xtreme detecta automáticamente en qué página gráfica se encuentra la pose y configura este bit de forma automática.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&#039;&#039;&#039;Size&#039;&#039;&#039;: define el tamaño del tile:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;$00: tile pequeño (8x8).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;$02: tile grande (16x16).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Además, cada tile posee:&lt;br /&gt;
&lt;br /&gt;
* X displacement (X Offset)&lt;br /&gt;
* Y displacement (Y Offset)&lt;br /&gt;
&lt;br /&gt;
Estos valores permiten mover el tile respecto a la posición base del sprite.&lt;br /&gt;
&lt;br /&gt;
Actualmente, Dynamic Xtreme posee 2 formatos DrawInfo: el formato actual y el formato legacy.&lt;br /&gt;
&lt;br /&gt;
=== Formato Actual ===&lt;br /&gt;
&lt;br /&gt;
El formato actual de DrawInfo fue diseñado para mejorar considerablemente la legibilidad y facilidad de mantenimiento de los archivos de dibujo.&lt;br /&gt;
&lt;br /&gt;
A diferencia del formato legacy, este sistema permite:&lt;br /&gt;
&lt;br /&gt;
* Agrupar múltiples poses.&lt;br /&gt;
* Agrupar rangos de tiles.&lt;br /&gt;
* Utilizar valores por defecto individuales.&lt;br /&gt;
* Omitir subtables innecesarias.&lt;br /&gt;
* Definir valores individuales o listas completas de valores.&lt;br /&gt;
&lt;br /&gt;
Ejemplo:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MyPose_Pose0..4:&lt;br /&gt;
.NumberOfTiles: 5&lt;br /&gt;
.TileCode2: $02&lt;br /&gt;
.TileCode3..4: $04&lt;br /&gt;
.Properties: $00,$40,$00,$00,$40&lt;br /&gt;
.XOffsets: $00,$10,$F8,$08,$18&lt;br /&gt;
.XPivot: $08&lt;br /&gt;
.YOffset2..4: $10&lt;br /&gt;
.YPivot: $10&lt;br /&gt;
.Size0..4: $02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;MyPose_Pose0..4&#039;&#039;&#039;: Define información compartida para las poses 0 hasta 4 que comparten el nombre &amp;quot;MyPose&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;.NumberOfTiles&#039;&#039;&#039;: Define que cada pose utiliza 5 tiles.&lt;br /&gt;
* &#039;&#039;&#039;.TileCode2&#039;&#039;&#039;: Modifica el &#039;&#039;&#039;TileCode&#039;&#039;&#039; únicamente del tile 2.&lt;br /&gt;
* &#039;&#039;&#039;.TileCode3..4&#039;&#039;&#039;: Modifica el &#039;&#039;&#039;TileCode&#039;&#039;&#039; de los tiles 3 y 4.&lt;br /&gt;
* &#039;&#039;&#039;.Properties&#039;&#039;&#039;: Define una lista individual de &#039;&#039;&#039;Properties&#039;&#039;&#039; para cada tile.&lt;br /&gt;
* &#039;&#039;&#039;.XOffsets&#039;&#039;&#039;: Define un &#039;&#039;&#039;XOffset&#039;&#039;&#039; individual para cada tile.&lt;br /&gt;
* &#039;&#039;&#039;.YOffset2..4&#039;&#039;&#039;: Modifica el &#039;&#039;&#039;YOffset&#039;&#039;&#039; únicamente de los tiles 2 al 4.&lt;br /&gt;
* &#039;&#039;&#039;.Size0..4&#039;&#039;&#039;: Define el tamaño de los tiles 0 al 4.&lt;br /&gt;
&lt;br /&gt;
Los tiles se numeran desde 0. Por ejemplo, con &amp;lt;code&amp;gt;.NumberOfTiles: 5&amp;lt;/code&amp;gt;, los tiles disponibles son del 0 al 4.&lt;br /&gt;
&lt;br /&gt;
Las directivas utilizadas en singular permiten modificar un tile específico o un rango de tiles determinado.&lt;br /&gt;
&lt;br /&gt;
Ejemplos:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.TileCode2: $02&lt;br /&gt;
.TileCode3..4: $04&lt;br /&gt;
.YOffset1..3: $10&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En estos casos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;.TileCode2:&#039;&#039;&#039;: Modifica únicamente el tile 2&lt;br /&gt;
* &#039;&#039;&#039;.TileCode3..4&#039;&#039;&#039;: Modifica únicamente los tiles 3 y 4&lt;br /&gt;
* &#039;&#039;&#039;.YOffset1..3&#039;&#039;&#039;: Modifica el YOffset de los tiles 1 al 3&lt;br /&gt;
&lt;br /&gt;
Por otro lado, las directivas en plural permiten definir explícitamente una lista completa de valores para todos los tiles de la pose.&lt;br /&gt;
&lt;br /&gt;
Ejemplos:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.Properties: $00,$40,$00,$00,$40&lt;br /&gt;
.XOffsets: $00,$10,$F8,$08,$18&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En estos casos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;.Properties&#039;&#039;&#039;: define una lista completa de Properties.&lt;br /&gt;
* &#039;&#039;&#039;.XOffsets&#039;&#039;&#039;: define una lista completa de XOffsets.&lt;br /&gt;
&lt;br /&gt;
Esto permite combinar configuraciones generales simples con modificaciones específicas únicamente donde sean necesarias.&lt;br /&gt;
&lt;br /&gt;
Las declaraciones se aplican en el orden en que aparecen. Si varias modifican el mismo atributo de un tile, se utiliza el último valor indicado. Por ejemplo, después de &amp;lt;code&amp;gt;.Properties: $00,$40,$00,$00,$40&amp;lt;/code&amp;gt;, puedes escribir &amp;lt;code&amp;gt;.Property2: $80&amp;lt;/code&amp;gt; para cambiar únicamente la propiedad del tile 2 a &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;. Si escribes la lista completa después, esa lista reemplazará los valores anteriores de todos los tiles.&lt;br /&gt;
&lt;br /&gt;
Cuando un valor no es definido explícitamente, Dynamic Xtreme utiliza automáticamente valores por defecto:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;TileCode&#039;&#039;&#039;:  $00&lt;br /&gt;
* &#039;&#039;&#039;Property&#039;&#039;&#039;:  $00&lt;br /&gt;
* &#039;&#039;&#039;XOffset&#039;&#039;&#039;:   $00&lt;br /&gt;
* &#039;&#039;&#039;YOffset&#039;&#039;&#039;:   $00&lt;br /&gt;
* &#039;&#039;&#039;Size&#039;&#039;&#039;:      $02&lt;br /&gt;
&lt;br /&gt;
A diferencia del formato legacy, estos valores por defecto funcionan de forma individual por tile, permitiendo omitir únicamente la información necesaria sin afectar el resto de la pose.&lt;br /&gt;
&lt;br /&gt;
Los offsets indican dónde se coloca cada tile respecto a la posición del sprite, en píxeles. Sin volteo, se suma &amp;lt;code&amp;gt;XOffset&amp;lt;/code&amp;gt; a la posición X del sprite y &amp;lt;code&amp;gt;YOffset&amp;lt;/code&amp;gt; a su posición Y. Por ejemplo, un &amp;lt;code&amp;gt;XOffset&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; coloca el tile 16 píxeles a la derecha; &amp;lt;code&amp;gt;$F8&amp;lt;/code&amp;gt; representa −8 y lo coloca 8 píxeles a la izquierda.&lt;br /&gt;
&lt;br /&gt;
Los valores &#039;&#039;&#039;XPivot&#039;&#039;&#039; y &#039;&#039;&#039;YPivot&#039;&#039;&#039; permiten calcular dónde deben colocarse los tiles al voltear toda la pose horizontal o verticalmente. No giran la pose: se utilizan para reflejar su distribución.&lt;br /&gt;
&lt;br /&gt;
Para el volteo horizontal, el cálculo equivale a estos pasos:&lt;br /&gt;
&lt;br /&gt;
# Se toma la posición X del sprite.&lt;br /&gt;
# Se le suma &amp;lt;code&amp;gt;XPivot&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Se resta el &amp;lt;code&amp;gt;XOffset&amp;lt;/code&amp;gt; original del tile, para invertir su desplazamiento.&lt;br /&gt;
# Si el tile es de 16×16, se restan otros 8 píxeles para ajustar su posición según su tamaño. Para un tile de 8×8 no se hace este ajuste.&lt;br /&gt;
&lt;br /&gt;
Por tanto, la posición X del tile volteado es:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tile de 8×8:&#039;&#039;&#039; &amp;lt;code&amp;gt;X del sprite + XPivot − XOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Tile de 16×16:&#039;&#039;&#039; &amp;lt;code&amp;gt;X del sprite + XPivot − XOffset − 8&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, una pose tiene dos tiles de 16×16 con &amp;lt;code&amp;gt;XOffset&amp;lt;/code&amp;gt; de 0 y 16. Si defines &amp;lt;code&amp;gt;.XPivot: $18&amp;lt;/code&amp;gt; (24 en decimal), sus posiciones se intercambian al voltear la pose:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tile !! Sin volteo !! Con volteo horizontal&lt;br /&gt;
|-&lt;br /&gt;
| Primero: XOffset = 0&lt;br /&gt;
| X del sprite + 0&lt;br /&gt;
| X del sprite + 24 − 0 − 8 = X del sprite + 16&lt;br /&gt;
|-&lt;br /&gt;
| Segundo: XOffset = 16&lt;br /&gt;
| X del sprite + 16&lt;br /&gt;
| X del sprite + 24 − 16 − 8 = X del sprite + 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para el volteo vertical se hace el mismo cálculo, usando la posición Y del sprite, &amp;lt;code&amp;gt;YPivot&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;YOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Estos desplazamientos para el volteo se calculan durante la instalación. Durante el juego, la rutina de dibujo utiliza los que corresponden al volteo solicitado.&lt;br /&gt;
&lt;br /&gt;
Si &#039;&#039;&#039;XPivot&#039;&#039;&#039; no es definido, la pose no será considerada compatible con flip horizontal. Del mismo modo, si &#039;&#039;&#039;YPivot&#039;&#039;&#039; no es definido, la pose no será considerada compatible con flip vertical.&lt;br /&gt;
&lt;br /&gt;
Esto permite que Dynamic Xtreme genere rutinas gráficas más optimizadas cuando estas características no son necesarias, además de reducir ligeramente el espacio utilizado dentro del ROM.&lt;br /&gt;
&lt;br /&gt;
También es posible utilizar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.IsStatic&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esto indica que las poses definidas deben considerarse poses estáticas en lugar de dinámicas. Por defecto, todas las poses son tratadas como dinámicas.&lt;br /&gt;
&lt;br /&gt;
El formato legacy de DrawInfo continúa siendo totalmente compatible. El formato moderno existe principalmente para simplificar la escritura, lectura y mantenimiento de archivos DrawInfo, manteniendo al mismo tiempo un alto nivel de flexibilidad.&lt;br /&gt;
&lt;br /&gt;
=== Formato Legacy ===&lt;br /&gt;
&lt;br /&gt;
El formato legacy de DrawInfo utiliza múltiples tablas separadas para definir cada atributo de los tiles utilizados por una pose.&lt;br /&gt;
&lt;br /&gt;
Este formato fue diseñado siguiendo una estructura similar a la utilizada normalmente al escribir rutinas gráficas manuales para sprites en SNES. La idea original era que las personas que ya estaban acostumbradas a desarrollar sprites de esta forma pudieran trabajar con DrawInfo utilizando una organización familiar y relativamente intuitiva para ese workflow tradicional.&lt;br /&gt;
&lt;br /&gt;
Ejemplo:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dynamic: &lt;br /&gt;
true&lt;br /&gt;
&lt;br /&gt;
Tiles:&lt;br /&gt;
MyPose0_Tiles:&lt;br /&gt;
    db $00&lt;br /&gt;
MyPose1_Tiles:&lt;br /&gt;
    db $00&lt;br /&gt;
&lt;br /&gt;
Properties:&lt;br /&gt;
MyPose0_Properties:&lt;br /&gt;
    db $00&lt;br /&gt;
MyPose1_Properties:&lt;br /&gt;
    db $00&lt;br /&gt;
&lt;br /&gt;
XDisplacements:&lt;br /&gt;
MyPose0_XDisp:&lt;br /&gt;
    db $00&lt;br /&gt;
MyPose1_XDisp:&lt;br /&gt;
    db $00&lt;br /&gt;
MyPose0_XDispFlip:&lt;br /&gt;
    db $00&lt;br /&gt;
MyPose1_XDispFlip:&lt;br /&gt;
    db $00&lt;br /&gt;
&lt;br /&gt;
YDisplacements:&lt;br /&gt;
MyPose0_YDisp:&lt;br /&gt;
    db $01&lt;br /&gt;
MyPose1_YDisp:&lt;br /&gt;
    db $01&lt;br /&gt;
MyPose0_YDispFlip:&lt;br /&gt;
    db $FF&lt;br /&gt;
MyPose1_YDispFlip:&lt;br /&gt;
    db $FF&lt;br /&gt;
&lt;br /&gt;
Sizes:&lt;br /&gt;
MyPose0_Sizes:&lt;br /&gt;
    db $02&lt;br /&gt;
MyPose1_Sizes:&lt;br /&gt;
    db $02&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este formato:&lt;br /&gt;
&lt;br /&gt;
* Cada atributo utiliza una sección independiente&lt;br /&gt;
* Cada pose requiere una subtabla separada&lt;br /&gt;
* Todos los valores deben escribirse manualmente&lt;br /&gt;
* No existen rangos de tiles ni agrupación de poses&lt;br /&gt;
&lt;br /&gt;
Las tablas principales corresponden a:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tiles&#039;&#039;&#039;: TileCodes&lt;br /&gt;
* &#039;&#039;&#039;Properties&#039;&#039;&#039;: Properties de OAM&lt;br /&gt;
* &#039;&#039;&#039;XDisplacements&#039;&#039;&#039;: Desplazamientos horizontales&lt;br /&gt;
* &#039;&#039;&#039;YDisplacements&#039;&#039;&#039;: Desplazamientos verticales&lt;br /&gt;
* &#039;&#039;&#039;Sizes&#039;&#039;&#039;: Tamaño de los tiles (8x8 o 16x16)&lt;br /&gt;
&lt;br /&gt;
En el caso de XDisplacements y YDisplacements, también es posible definir versiones flippeadas:&lt;br /&gt;
&lt;br /&gt;
* XDispFlip&lt;br /&gt;
* YDispFlip&lt;br /&gt;
&lt;br /&gt;
Estas tablas permiten especificar manualmente los offsets utilizados cuando una pose es dibujada utilizando flip horizontal o vertical.&lt;br /&gt;
&lt;br /&gt;
La directiva:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dynamic: true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Indica que las poses deben ser tratadas como poses dinámicas. Si se define como false, las poses serán consideradas estáticas.&lt;br /&gt;
&lt;br /&gt;
Al igual que en el formato moderno, existen valores por defecto automáticos. Si alguna tabla no existe, Dynamic Xtreme asumirá automáticamente los siguientes valores:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;TileCode&#039;&#039;&#039;:  $00&lt;br /&gt;
* &#039;&#039;&#039;Property&#039;&#039;&#039;:  $00&lt;br /&gt;
* &#039;&#039;&#039;XOffset&#039;&#039;&#039;:   $00&lt;br /&gt;
* &#039;&#039;&#039;YOffset&#039;&#039;&#039;:   $00&lt;br /&gt;
* &#039;&#039;&#039;Size&#039;&#039;&#039;:      $02&lt;br /&gt;
&lt;br /&gt;
Este formato continúa siendo totalmente compatible con Dynamic Xtreme, aunque actualmente se recomienda utilizar el formato moderno debido a que resulta considerablemente más legible, mantenible y fácil de editar.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_Quick_Start&amp;diff=21379</id>
		<title>es/Dynamic Xtreme Quick Start</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_Quick_Start&amp;diff=21379"/>
		<updated>2026-10-25T07:20:48Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_Quick_Start}}&lt;br /&gt;
&lt;br /&gt;
Esta guía explica cómo realizar una instalación básica de Dynamic&lt;br /&gt;
Xtreme en Windows o Linux.&lt;br /&gt;
&lt;br /&gt;
Si es la primera vez que utilizas la herramienta, sigue los pasos en&lt;br /&gt;
el orden indicado. No es necesario conocer el funcionamiento interno&lt;br /&gt;
del sistema para completar la instalación.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme requiere el runtime de .NET 8. Descarga e instala la&lt;br /&gt;
versión correspondiente a tu sistema operativo desde el sitio oficial&lt;br /&gt;
de Microsoft:&lt;br /&gt;
&lt;br /&gt;
[https://dotnet.microsoft.com/download/dotnet/8.0 .NET 8 Runtime]&lt;br /&gt;
&lt;br /&gt;
La herramienta es compatible con Windows y Linux. Solo necesitas el&lt;br /&gt;
runtime de .NET; no es necesario instalar el SDK completo.&lt;br /&gt;
&lt;br /&gt;
Puedes descargar Dynamic Xtreme desde SNEStorage: [https://snestorage.dev/Resource/7 SNEStorage - Dynamic Xtreme]&lt;br /&gt;
&lt;br /&gt;
== Preparar los recursos ==&lt;br /&gt;
&lt;br /&gt;
Antes de ejecutar Dynamic Xtreme, añade a tu proyecto todos los&lt;br /&gt;
recursos que deseas instalar.&lt;br /&gt;
&lt;br /&gt;
=== Recursos para PIXI y UberASMTool ===&lt;br /&gt;
&lt;br /&gt;
Los recursos actuales normalmente incluyen su archivo&lt;br /&gt;
&amp;lt;code&amp;gt;*.asm&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;*.json&amp;lt;/code&amp;gt; junto con los archivos que&lt;br /&gt;
necesitan. Copia el paquete completo sin cambiar su estructura de&lt;br /&gt;
carpetas.&lt;br /&gt;
&lt;br /&gt;
En PIXI, utiliza la carpeta correspondiente al tipo de sprite:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprites&amp;lt;/code&amp;gt; para sprites normales.&lt;br /&gt;
* &amp;lt;code&amp;gt;cluster&amp;lt;/code&amp;gt; para cluster sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;extended&amp;lt;/code&amp;gt; para extended sprites.&lt;br /&gt;
* Para otros tipos, utiliza la carpeta indicada por el recurso.&lt;br /&gt;
&lt;br /&gt;
En UberASMTool, utiliza la carpeta correspondiente al tipo de código:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;level&amp;lt;/code&amp;gt; para códigos de nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;overworld&amp;lt;/code&amp;gt; para códigos del overworld.&lt;br /&gt;
* &amp;lt;code&amp;gt;gamemode&amp;lt;/code&amp;gt; para códigos de game mode.&lt;br /&gt;
* Para otros tipos, utiliza la carpeta indicada por el recurso.&lt;br /&gt;
&lt;br /&gt;
Después de copiar el recurso, añádelo al archivo de lista de PIXI o&lt;br /&gt;
UberASMTool como lo harías normalmente.&lt;br /&gt;
&lt;br /&gt;
Los recursos preparados para Dynamic Xtreme ya contienen las&lt;br /&gt;
declaraciones necesarias en su archivo ASM principal. Mantén juntos&lt;br /&gt;
el ASM, el JSON y las carpetas incluidas con el recurso para no romper&lt;br /&gt;
sus rutas relativas.&lt;br /&gt;
&lt;br /&gt;
=== Carpetas tradicionales ===&lt;br /&gt;
&lt;br /&gt;
Algunos recursos utilizan las carpetas tradicionales de Dynamic&lt;br /&gt;
Xtreme. En ese caso, sigue esta organización:&lt;br /&gt;
&lt;br /&gt;
Estas carpetas se encuentran junto al ejecutable de Dynamic Xtreme: &amp;lt;code&amp;gt;dxt.exe&amp;lt;/code&amp;gt; en Windows o &amp;lt;code&amp;gt;dxt&amp;lt;/code&amp;gt; en Linux.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tipo de archivo&lt;br /&gt;
! Carpeta&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;DynamicInfos&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;DrawInfos&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteEffects&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gráficos, paletas y otros archivos relacionados&lt;br /&gt;
| &amp;lt;code&amp;gt;DynamicResources&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Utiliza siempre el método indicado por el recurso. No muevas a las&lt;br /&gt;
carpetas tradicionales los archivos de un sprite o código UberASM&lt;br /&gt;
moderno, salvo que sus instrucciones lo soliciten.&lt;br /&gt;
&lt;br /&gt;
== Instalación completa ==&lt;br /&gt;
&lt;br /&gt;
=== Ejecutar la herramienta ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme debe ejecutarse desde su propia carpeta.&lt;br /&gt;
&lt;br /&gt;
* En Windows, haz doble clic en &amp;lt;code&amp;gt;dxt.exe&amp;lt;/code&amp;gt;.&lt;br /&gt;
* En Linux, abre una terminal en la carpeta de Dynamic Xtreme y ejecuta:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./dxt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La herramienta mostrará una serie de preguntas para configurar la&lt;br /&gt;
instalación.&lt;br /&gt;
&lt;br /&gt;
=== Configurar las rutas ===&lt;br /&gt;
&lt;br /&gt;
Las rutas y las funcionalidades seleccionadas quedan guardadas en &amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt;, dentro de la carpeta de Dynamic Xtreme. La herramienta utiliza ese archivo para recuperar la configuración en las siguientes instalaciones.&lt;br /&gt;
&lt;br /&gt;
Puedes escribir cada ruta o arrastrar el archivo correspondiente a la&lt;br /&gt;
terminal. Después, presiona Enter para continuar.&lt;br /&gt;
&lt;br /&gt;
Si dejas una respuesta vacía y presionas Enter, Dynamic Xtreme&lt;br /&gt;
utilizará el valor guardado en &amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt;. Si todavía no&lt;br /&gt;
existe un valor guardado y la ruta es opcional, esa integración se&lt;br /&gt;
omitirá.&lt;br /&gt;
&lt;br /&gt;
Las rutas se solicitan en el siguiente orden:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;ROM de entrada&#039;&#039;&#039;&lt;br /&gt;
#: Selecciona la ROM de Super Mario World que deseas modificar.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;ROM de salida&#039;&#039;&#039;&lt;br /&gt;
#: Indica la ruta de la ROM que tendrá el resultado de la instalación.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Ejecutable de PIXI&#039;&#039;&#039;&lt;br /&gt;
#: Selecciona el ejecutable de PIXI. Esta ruta permite integrar las&lt;br /&gt;
#: rutinas y definiciones de Dynamic Xtreme con PIXI.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Ejecutable de UberASMTool&#039;&#039;&#039;&lt;br /&gt;
#: Selecciona el ejecutable de UberASMTool si tu proyecto utiliza&lt;br /&gt;
#: códigos de UberASM.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Ejecutable de GPS&#039;&#039;&#039;&lt;br /&gt;
#: Selecciona el ejecutable de GPS si tu proyecto utiliza bloques&lt;br /&gt;
#: personalizados.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Lista de PIXI&#039;&#039;&#039;&lt;br /&gt;
#: Selecciona el archivo de lista donde registraste los sprites que&lt;br /&gt;
#: utilizará tu proyecto.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Lista de UberASMTool&#039;&#039;&#039;&lt;br /&gt;
#: Selecciona el archivo de lista donde registraste los códigos&lt;br /&gt;
#: UberASM que utilizará tu proyecto.&lt;br /&gt;
&lt;br /&gt;
Las rutas de PIXI, UberASMTool, GPS y sus listas son opcionales.&lt;br /&gt;
Si no utilizas alguna de estas herramientas y no existe una ruta&lt;br /&gt;
guardada, puedes dejar la respuesta vacía.&lt;br /&gt;
&lt;br /&gt;
Para dejar de utilizar una integración que ya tiene rutas guardadas, edita &amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt; y deja sus valores como cadenas vacías (&amp;lt;code&amp;gt;&amp;quot;&amp;quot;&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
* PIXI: &amp;lt;code&amp;gt;PixiPath&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PixiListPath&amp;lt;/code&amp;gt;.&lt;br /&gt;
* UberASMTool: &amp;lt;code&amp;gt;UberasmToolPath&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;UberasmListPath&amp;lt;/code&amp;gt;.&lt;br /&gt;
* GPS: &amp;lt;code&amp;gt;GPSPath&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
No elimines los campos ni reemplaces todo el archivo. En las siguientes preguntas podrás dejar esas rutas vacías sin recuperar la integración anterior.&lt;br /&gt;
&lt;br /&gt;
=== Seleccionar las funciones ===&lt;br /&gt;
&lt;br /&gt;
Después de configurar las rutas, Dynamic Xtreme preguntará qué&lt;br /&gt;
funciones deseas instalar.&lt;br /&gt;
&lt;br /&gt;
Puedes responder &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt; para habilitar una función o&lt;br /&gt;
&amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; para deshabilitarla.&lt;br /&gt;
&lt;br /&gt;
Si presionas Enter sin escribir nada, se conservará el valor guardado&lt;br /&gt;
en &amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt;. Durante la primera instalación se utilizará&lt;br /&gt;
el valor predeterminado de la función.&lt;br /&gt;
&lt;br /&gt;
En una instalación habitual se pueden habilitar las funciones que no&lt;br /&gt;
muestran advertencias. Si aparece una advertencia en rojo, léela con&lt;br /&gt;
atención y comprueba su compatibilidad con tu proyecto antes de&lt;br /&gt;
habilitar esa función.&lt;br /&gt;
&lt;br /&gt;
Consulta [[es/Dynamic_Xtreme#Funcionalidades|Funcionalidades]] para saber qué hace cada opción y [[es/Dynamic_Xtreme#Compatibilidad|Compatibilidad]] para revisar los posibles conflictos con otros recursos y los espacios de RAM utilizados.&lt;br /&gt;
&lt;br /&gt;
=== Ejemplo de instalación típica con PIXI y UberASMTool ===&lt;br /&gt;
&lt;br /&gt;
Este ejemplo utiliza PIXI y UberASMTool con las opciones predeterminadas. Las rutas son ficticias y corresponden a Windows; sustitúyelas por las de tu proyecto. En Linux, indica las rutas de sus ejecutables correspondientes.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Pregunta !! Ejemplo de respuesta&lt;br /&gt;
|-&lt;br /&gt;
| ROM de entrada || &amp;lt;code&amp;gt;C:\MiHack\MiHack.smc&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| ROM de salida || &amp;lt;code&amp;gt;C:\MiHack\MiHack_DX.smc&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ejecutable de PIXI || &amp;lt;code&amp;gt;C:\MiHack\PIXI\pixi.exe&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ejecutable de UberASMTool || &amp;lt;code&amp;gt;C:\MiHack\UberASMTool\UberASMTool.exe&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ejecutable de GPS || Dejar vacío si no se utiliza y no hay una ruta guardada.&lt;br /&gt;
|-&lt;br /&gt;
| Lista de PIXI || &amp;lt;code&amp;gt;C:\MiHack\PIXI\list.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Lista de UberASMTool || &amp;lt;code&amp;gt;C:\MiHack\UberASMTool\list.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para las funcionalidades, utiliza estos valores:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Activada !! Respuesta&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt; || Sí || &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt; || No || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt; || No || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; || No || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; || No || &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
En ROMs con SA-1, &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; se desactiva automáticamente.&lt;br /&gt;
&lt;br /&gt;
Enter conserva el valor guardado si ya utilizaste la herramienta. Para reproducir esta configuración, responde &amp;lt;code&amp;gt;Y&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; según la tabla; los valores predeterminados solo se utilizan cuando no hay una selección anterior.&lt;br /&gt;
&lt;br /&gt;
== Instalación mediante línea de comandos ==&lt;br /&gt;
&lt;br /&gt;
Después de completar una instalación interactiva, Dynamic Xtreme&lt;br /&gt;
guarda las rutas y funciones seleccionadas en&lt;br /&gt;
&amp;lt;code&amp;gt;Settings/Settings.json&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Puedes reutilizar esa configuración para realizar instalaciones&lt;br /&gt;
posteriores sin responder nuevamente todas las preguntas.&lt;br /&gt;
&lt;br /&gt;
En Windows, abre una terminal en la carpeta de Dynamic Xtreme y&lt;br /&gt;
ejecuta:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.\dxt.exe -use-settings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En Linux, ejecuta:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./dxt -use-settings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si alguna ruta guardada ya no es válida, Dynamic Xtreme volverá al&lt;br /&gt;
modo interactivo para solicitar la configuración.&lt;br /&gt;
&lt;br /&gt;
Las opciones disponibles son:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Opción&lt;br /&gt;
! Alias&lt;br /&gt;
! Descripción&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-use-settings&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;-us&amp;lt;/code&amp;gt;&lt;br /&gt;
| Utiliza las rutas y funciones guardadas sin mostrar nuevamente las&lt;br /&gt;
preguntas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-verbose&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;-v&amp;lt;/code&amp;gt;&lt;br /&gt;
| Muestra información más detallada durante la instalación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-help&amp;lt;/code&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
| Muestra la ayuda y la lista de opciones disponibles.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-version&amp;lt;/code&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
| Muestra la versión instalada de Dynamic Xtreme.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las opciones pueden combinarse. Por ejemplo, para utilizar la&lt;br /&gt;
configuración guardada y mostrar información detallada:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Windows:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.\dxt.exe -use-settings -verbose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Linux:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./dxt -use-settings -verbose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para cambiar las rutas o las funciones seleccionadas, ejecuta Dynamic&lt;br /&gt;
Xtreme sin &amp;lt;code&amp;gt;-use-settings&amp;lt;/code&amp;gt; y completa nuevamente las&lt;br /&gt;
preguntas.&lt;br /&gt;
&lt;br /&gt;
== Finalizar la instalación ==&lt;br /&gt;
&lt;br /&gt;
Tanto la instalación interactiva como la instalación mediante línea&lt;br /&gt;
de comandos producen el mismo resultado.&lt;br /&gt;
&lt;br /&gt;
El resultado de la instalación queda guardado en &amp;lt;code&amp;gt;log.txt&amp;lt;/code&amp;gt;, junto al ejecutable de Dynamic Xtreme. Este archivo contiene todos los detalles de la instalación.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme prepara la integración con PIXI, UberASMTool y GPS,&lt;br /&gt;
pero no ejecuta estas herramientas. Después de instalar Dynamic&lt;br /&gt;
Xtreme, vuelve a ejecutar las herramientas externas que utilice tu&lt;br /&gt;
proyecto sobre la ROM de salida.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cuándo reinstalar:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Si cambias gráficos, paletas o archivos &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;, reinstala Dynamic Xtreme y después las herramientas que utilicen esos recursos.&lt;br /&gt;
* Si solo modificas el &amp;lt;code&amp;gt;*.asm&amp;lt;/code&amp;gt;, no necesitas reinstalar Dynamic Xtreme. Basta con volver a insertar el código con la herramienta correspondiente.&lt;br /&gt;
&lt;br /&gt;
Cuando sea necesario reinstalar Dynamic Xtreme, el orden correcto es:&lt;br /&gt;
&lt;br /&gt;
# Ejecutar Dynamic Xtreme para regenerar e instalar sus recursos.&lt;br /&gt;
# Volver a ejecutar PIXI, UberASMTool, GPS y cualquier otra&lt;br /&gt;
#: herramienta que utilice datos generados por Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Este orden es necesario porque las direcciones y los identificadores&lt;br /&gt;
de los recursos pueden cambiar cada vez que se ejecuta Dynamic&lt;br /&gt;
Xtreme.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21378</id>
		<title>es/Dynamic Xtreme</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21378"/>
		<updated>2026-10-25T07:04:48Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es una herramienta de soporte dinámico avanzada para Super Mario World en el SNES. Desarrollada para la comunidad de ROM hacking, permite realizar cambios gráficos y de paletas en tiempo real durante la ejecución del juego. La herramienta se centra en ofrecer un sistema completo y flexible de gráficos dinámicos, con énfasis en el rendimiento y la modularidad.&lt;br /&gt;
&lt;br /&gt;
Un sprite dinámico carga recursos, como gráficos o paletas, en tiempo real durante el juego. En cambio, un sprite estático utiliza los recursos que ya estaban cargados al comenzar el nivel.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme no rompe los límites del hardware de SNES: trabaja dentro de ellos y optimiza el uso de la memoria y las transferencias para reducir su impacto y hacer que sean mucho menos perceptibles durante el juego.&lt;br /&gt;
&lt;br /&gt;
Entre sus características principales se incluyen:&lt;br /&gt;
* Cambios gráficos y de paleta en tiempo real (on-the-fly).&lt;br /&gt;
* El sistema de Dynamic Sprite más potente y flexible disponible para Super Mario World.&lt;br /&gt;
* Advanced Drawing System, que permite dibujar cualquier frame registrado en pantalla con control total sobre prioridad, capa, desplazamiento (offset) y propiedades.&lt;br /&gt;
* Efectos de paleta avanzados, que incluyen modificación en tiempo real mediante tono (hue), saturación, brillo, fusión de colores, transiciones suaves y control individual de canales RGB y HSL.&lt;br /&gt;
* Reemplazo completo de gráficos y paletas del jugador, compatible con cualquier tamaño de Mario, cualquier cantidad de frames y cualquier estilo de animación.&lt;br /&gt;
* Reemplazo de gráficos de Yoshi usando un layout como el del juego original.&lt;br /&gt;
* Optimizaciones intensivas en el NMI-handler para maximizar el rendimiento.&lt;br /&gt;
&lt;br /&gt;
Las funciones de Dynamic Xtreme se seleccionan durante la instalación para utilizar solo las que necesita el proyecto. Algunas tienen dependencias, problemas de compatibilidad o restricciones para desinstalarlas; revisa las advertencias de cada opción. La herramienta fue creada con el objetivo de facilitar la implementación de efectos visuales complejos en hacks de Super Mario World manteniendo un alto nivel de compatibilidad y estabilidad.&lt;br /&gt;
&lt;br /&gt;
== Objetivos del proyecto ==&lt;br /&gt;
&lt;br /&gt;
El principal objetivo de Dynamic Xtreme es facilitar el uso de sprites dinámicos y ofrecer un soporte completo para cambios de gráficos, paletas y tilemaps en tiempo real.&lt;br /&gt;
&lt;br /&gt;
El proyecto busca aprovechar al máximo el potencial del SNES sin requerir que el usuario tenga conocimientos avanzados sobre el hardware interno de la consola. Muchos sistemas dinámicos tradicionales suelen ser complejos y dependen fuertemente de conceptos técnicos como VRAM, CGRAM, OAM o DMA. Dynamic Xtreme intenta abstraer gran parte de esa complejidad mediante herramientas y formatos más modernos, legibles y fáciles de utilizar.&lt;br /&gt;
&lt;br /&gt;
Otro de los objetivos principales del proyecto es mantener un alto rendimiento incluso en situaciones visualmente complejas, permitiendo el uso intensivo de gráficos dinámicos, efectos de paletas y sistemas avanzados de renderizado sin comprometer innecesariamente la performance.&lt;br /&gt;
&lt;br /&gt;
Además, Dynamic Xtreme busca que los sprites dinámicos puedan utilizarse de una forma tan natural y sencilla como si fueran sprites normales. La idea es que las personas enfocadas en level design o creación de contenido no necesiten preocuparse constantemente por las limitaciones técnicas internas del sistema y puedan trabajar con recursos dinámicos de forma transparente y práctica.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades ==&lt;br /&gt;
&lt;br /&gt;
Durante la instalación puedes elegir qué funcionalidades habilitar. Los nombres entre paréntesis corresponden a las opciones del instalador y de &amp;lt;code&amp;gt;Settings.json&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Gráficos, poses y paletas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de gráficos (&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;) || Permite cargar gráficos durante el juego. Es la base para las animaciones de tiles, los cambios de gráficos del nivel y las poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de paletas (&amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;) || Permite cargar y administrar paletas durante el juego. Incluye la asignación automática de paletas para que los sprites puedan compartir los mismos colores sin cargarlos varias veces.&lt;br /&gt;
|-&lt;br /&gt;
| Poses dinámicas (&amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;) || Administra el espacio de VRAM como una caché de poses: reutiliza las que ya están cargadas, permite compartirlas entre entidades y elige cuáles reemplazar cuando hace falta espacio. Así evita cargas innecesarias.&lt;br /&gt;
|-&lt;br /&gt;
| Dibujo de poses (&amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;) || Dibuja las poses definidas en archivos DrawInfo, tanto dinámicas como estáticas. Permite controlar sus tiles, posición, volteo, paleta y prioridad de dibujo.&lt;br /&gt;
|-&lt;br /&gt;
| Efectos de paleta (&amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;) || Permite cambiar colores mediante efectos RGB y HSL: teñir paletas, modificar tono, saturación o luminosidad, y realizar transiciones entre paletas. Pueden aplicarse a recursos individuales o como un efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La carga de poses dinámicas y el dibujo son sistemas separados: puedes dibujar una pose estática sin cargar sus gráficos dinámicamente.&lt;br /&gt;
&lt;br /&gt;
=== Jugador y Yoshi ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Funciones del jugador (&amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos y paletas del jugador y adaptar su dibujo y carga de poses a sistemas personalizados. También permite ocultarlo o desactivar sus cargas dinámicas. Puede entrar en conflicto con parches que modifican los gráficos o paletas del jugador; revisa la advertencia del instalador antes de habilitarla.&lt;br /&gt;
|-&lt;br /&gt;
| Funciones de Yoshi (&amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos de Yoshi manteniendo la organización de sus poses originales. Requiere &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memoria y optimizaciones ===&lt;br /&gt;
&lt;br /&gt;
Estas opciones reorganizan parte del trabajo del juego para dejar más tiempo disponible para las cargas de gráficos y paletas. NMI es la rutina que realiza las actualizaciones de pantalla durante la pausa entre un frame y el siguiente.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Liberar el área &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;) || En ROMs sin SA-1, evita mantener en RAM ciertos gráficos originales del jugador, Yoshi y animaciones, y permite leerlos desde ROM. Dynamic Xtreme utiliza el espacio recuperado para sus variables internas; no queda libre para usarlo sin reservar. Esta opción no se aplica a ROMs con SA-1.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del control (&amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;) || Mueve el procesamiento del control fuera de NMI para dejar más tiempo disponible para las actualizaciones de pantalla.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del color fijo (&amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI relacionado con la actualización del color fijo que utiliza el juego para sus mezclas de color.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de VRAM de Lunar Magic de Kevin (&amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;) || Integra la optimización de Kevin para las actualizaciones de VRAM de Lunar Magic y mueve parte de su procesamiento fuera de NMI. Utiliza esta versión en lugar del parche original por separado. Una vez instalada, no debe desinstalarse: hacerlo puede dañar el funcionamiento de la ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de la barra de estado (&amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI de la barra de estado original. No es compatible con recursos que la reemplazan o modifican, como barras de estado personalizadas o parches que la eliminan.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para revisar qué opciones pueden entrar en conflicto con otros recursos y qué RAM utiliza el sistema, consulta [[#Compatibilidad|Compatibilidad]].&lt;br /&gt;
&lt;br /&gt;
Algunas funcionalidades necesitan otras: &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; necesita ambas opciones de cambios gráficos y de paletas; y &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guía rápida de instalación:&#039;&#039;&#039; [[es/Dynamic_Xtreme_Quick_Start|Quick Start]]&lt;br /&gt;
&lt;br /&gt;
== Herramientas y Soporte ==&lt;br /&gt;
&lt;br /&gt;
Pendiente&lt;br /&gt;
&lt;br /&gt;
== Archivos y formatos ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Artículo relacionado:&#039;&#039;&#039; [[es/Dynamic_Xtreme_files_and_formats|Archivos y Formatos de Dynamic Xtreme]]&lt;br /&gt;
&lt;br /&gt;
== Guía de creación de sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Para aprender a preparar, programar, cargar y dibujar un sprite dinámico, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites dinámicos con Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
== Dynamic Xtreme con UberASM ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_UberASM_guide|guía de Dynamic Xtreme con UberASM]] muestra cómo reservar paletas, configurar el espacio para sprites dinámicos y el límite de datos por frame, crear animaciones, cambiar gráficos del jugador y aplicar efectos de paleta.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]] explica cómo utilizar las variables, los defines, las rutinas y las macros de Dynamic Xtreme. Incluye los datos que necesita cada llamada, sus resultados y ejemplos de uso para trabajar con poses, dibujo, paletas, efectos de color y transferencias de gráficos, además de las macros de multiplicación y división.&lt;br /&gt;
&lt;br /&gt;
== Funcionamiento interno del sistema ==&lt;br /&gt;
&lt;br /&gt;
El artículo sobre el [[es/Dynamic_Xtreme_internal_workings|funcionamiento interno de Dynamic Xtreme]] explica cómo se organizan NMI y los game modes, las cargas de gráficos y paletas, el dibujo de poses, las optimizaciones, la caché de poses dinámicas y los efectos de paleta.&lt;br /&gt;
&lt;br /&gt;
== Compatibilidad ==&lt;br /&gt;
&lt;br /&gt;
En general, las funcionalidades que no muestran warnings en el instalador no suelen presentar problemas de incompatibilidad con otros recursos. Estas son:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esto no garantiza que cualquier combinación de recursos funcione: dos códigos todavía pueden utilizar la misma RAM, el mismo espacio de VRAM o modificar la misma rutina del juego. Además, &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, por lo que también debes considerar las restricciones de esta última.&lt;br /&gt;
&lt;br /&gt;
=== Funcionalidades con restricciones de compatibilidad ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad opcional !! Posibles conflictos y qué hacer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; || Puede entrar en conflicto con &#039;&#039;&#039;LX5&#039;s Powerups&#039;&#039;&#039;, &#039;&#039;&#039;Player 8x8 tiles DMAer&#039;&#039;&#039;, &#039;&#039;&#039;Player 32x32&#039;&#039;&#039; y otros sistemas que reemplazan la carga de gráficos o paletas del jugador. &#039;&#039;&#039;Player Revolution&#039;&#039;&#039; sí es compatible. Si tu sistema de jugador necesita esas rutinas originales, deja esta opción deshabilitada; también tendrás que deshabilitar &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; || Depende de &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y hereda sus restricciones de compatibilidad, aunque no muestre un warning propio. Si otro recurso es incompatible con &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, no puedes evitar ese conflicto habilitando únicamente &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;: debes dejar ambas deshabilitadas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt; || No es compatible con recursos que modifican, reemplazan o eliminan la barra de estado original, como &#039;&#039;&#039;LX5&#039;s DKC Style Status Bar&#039;&#039;&#039;, &#039;&#039;&#039;Minimalistic Status Bar&#039;&#039;&#039; y &#039;&#039;&#039;Nuke Status Bar&#039;&#039;&#039;. Si utilizas uno de ellos, deja esta optimización deshabilitada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt; || Integra el parche de optimización de VRAM de Lunar Magic de Kevin: utiliza esta versión en lugar del parche original por separado. Su warning también indica que &#039;&#039;&#039;no debe desinstalarse después de instalarla&#039;&#039;&#039;, porque hacerlo puede romper el funcionamiento de la ROM. Si necesitas revertirla, restaura una copia de seguridad anterior a su instalación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas funcionalidades son opcionales: puedes dejar deshabilitada la que entra en conflicto y seguir utilizando los demás sistemas de Dynamic Xtreme, respetando sus dependencias. Deshabilitar una opción no deshace los cambios de otro parche ni elimina la restricción de desinstalación de &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Espacios de RAM utilizados ===&lt;br /&gt;
&lt;br /&gt;
Las direcciones principales se configuran en &amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt;, dentro de la carpeta de Dynamic Xtreme. En el repositorio, ese archivo corresponde a &amp;lt;code&amp;gt;DynamicXtremeLibrary/ASM/DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El espacio utilizado depende de las funcionalidades habilitadas y de si la ROM utiliza SA-1. Los siguientes rangos incluyen el primer y el último byte y están calculados con &#039;&#039;&#039;todas las funcionalidades que reservan RAM habilitadas&#039;&#039;&#039;, &amp;lt;code&amp;gt;!VRAMTransferSize = 64&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!CGRAMTransferSize = 64&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuración !! Bloque &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; !! Tamaño !! Bloque &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; !! Tamaño&lt;br /&gt;
|-&lt;br /&gt;
| LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2000–$7E2500&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7E2800–$7E3608&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB440–$7FB940&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7F9C80–$7FAA88&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C000–$40C47E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$047F&amp;lt;/code&amp;gt;: 1151 bytes || &amp;lt;code&amp;gt;$418AFF–$419907&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los dos bloques internos suman &#039;&#039;&#039;4874 bytes en LoROM&#039;&#039;&#039; y &#039;&#039;&#039;4744 bytes en SA-1&#039;&#039;&#039;. La diferencia se debe a los 130 bytes del sistema de dibujo que solo se reservan en LoROM. No se ocupa automáticamente el espacio que queda entre los bloques.&lt;br /&gt;
&lt;br /&gt;
Al deshabilitar una funcionalidad se eliminan sus reservas condicionales y cambian las direcciones posteriores. Aumentar &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; también aumenta el tamaño de sus tablas.&lt;br /&gt;
&lt;br /&gt;
==== Tablas utilizadas por los sprites ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; &#039;&#039;&#039;no son espacios disponibles para escribir variables propias&#039;&#039;&#039;: a partir de esas posiciones se ubican las tablas de sprites de &amp;lt;code&amp;gt;DynamicXSpritesTables.asm&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;MoreSpriteMiscs.asm&amp;lt;/code&amp;gt;. También debes reservarlas si utilizas esos recursos.&lt;br /&gt;
&lt;br /&gt;
Con la misma configuración de la tabla anterior, sus rangos son:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuración !! Tablas desde &amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; !! Tamaño !! Tablas desde &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; !! Tamaño&lt;br /&gt;
|-&lt;br /&gt;
| LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2501–$7E26EC&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7E3609–$7E3824&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB941–$7FBB2C&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7FAC82–$7FAE9D&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C47F–$40C6D8&amp;lt;/code&amp;gt; || 602 bytes || &amp;lt;code&amp;gt;$419908–$419BCD&amp;lt;/code&amp;gt; || 710 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Incluyendo estas tablas, el espacio descrito suma &#039;&#039;&#039;5906 bytes en LoROM&#039;&#039;&#039; y &#039;&#039;&#039;6056 bytes en SA-1&#039;&#039;&#039;. Las tablas se calculan para 12 sprites normales en LoROM y 22 en SA-1, además de los slots de cluster, extended y smoke correspondientes.&lt;br /&gt;
&lt;br /&gt;
Normalmente, &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; comienza justo después del segundo bloque interno. En LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; se coloca por separado mediante &amp;lt;code&amp;gt;!Variables3 = $7FAC82&amp;lt;/code&amp;gt;; por eso sus tablas no empiezan inmediatamente después de &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme también utiliza los espejos existentes del color fijo y de la paleta: &amp;lt;code&amp;gt;$7E0701&amp;lt;/code&amp;gt; (2 bytes) y &amp;lt;code&amp;gt;$7E0703&amp;lt;/code&amp;gt; (512 bytes) en LoROM. En SA-1 sus direcciones declaradas son &amp;lt;code&amp;gt;$406701&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$006703&amp;lt;/code&amp;gt;. No son reservas adicionales dentro de los bloques anteriores ni direcciones libres para tus códigos.&lt;br /&gt;
&lt;br /&gt;
==== Reubicar la RAM si hay un conflicto ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Advertencia:&#039;&#039;&#039; para reubicar estas variables debes saber qué dirección elegir y considerar el tamaño completo del espacio de memoria que utiliza el sistema. No basta con que una dirección esté libre: debe haber espacio suficiente y las rutinas deben poder acceder a él. Si no tienes conocimientos sobre esto, consulta con alguien que los tenga antes de modificar las direcciones.&lt;br /&gt;
&lt;br /&gt;
Si otro recurso utiliza alguno de estos espacios, puedes modificar &#039;&#039;&#039;&amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt;&#039;&#039;&#039; para hacer que Dynamic Xtreme utilice otras zonas disponibles de tu romhack.&lt;br /&gt;
&lt;br /&gt;
* Cambia &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; en la configuración correspondiente a tu ROM: LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, LoROM sin esa opción o SA-1.&lt;br /&gt;
* En LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, revisa también &amp;lt;code&amp;gt;!Variables3&amp;lt;/code&amp;gt;, que determina dónde empiezan las tablas de &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Reserva espacio suficiente para el bloque completo y las tablas de sprites que le siguen. No basta con que la primera dirección esté libre.&lt;br /&gt;
* Respeta el mapa de memoria y los bancos que necesitan las rutinas. No cualquier dirección libre sirve para cualquier acceso.&lt;br /&gt;
* Después de cambiar las direcciones, reinstala Dynamic Xtreme y vuelve a insertar PIXI, UberASM y los demás recursos que utilicen sus defines.&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, Dynamic Xtreme aprovecha el área de RAM que recupera al reubicar los gráficos originales; no la compartas con otros recursos sin comprobar qué parte utiliza. Sin esa opción, las direcciones alternativas pueden coincidir con las de otros recursos habituales. SA-1 utiliza sus propias direcciones y desactiva &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Modifica el archivo de la carpeta &#039;&#039;&#039;ASM&#039;&#039;&#039;, no las copias generadas en &amp;lt;code&amp;gt;ExtraDefines&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;Patch/ExtraDefines&amp;lt;/code&amp;gt;: esas copias se regeneran durante la instalación.&lt;br /&gt;
&lt;br /&gt;
== Recursos hechos con Dynamic Xtreme ==&lt;br /&gt;
&lt;br /&gt;
La mayoría de los recursos desarrollados para Dynamic Xtreme no suelen publicarse en sitios tradicionales como SMW Central debido a que muchos de ellos dependen directamente del framework y sus sistemas avanzados.&lt;br /&gt;
&lt;br /&gt;
En su lugar, los recursos, ejemplos, sistemas y proyectos relacionados con Dynamic Xtreme se encuentran recopilados principalmente en:&lt;br /&gt;
&lt;br /&gt;
https://snestorage.dev&lt;br /&gt;
&lt;br /&gt;
Allí es posible encontrar sprites, sistemas de jugador, efectos gráficos, ejemplos técnicos y otros recursos diseñados específicamente para trabajar con Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
== Conclusión ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es un proyecto orientado a modernizar y simplificar el uso de sistemas dinámicos en Super Mario World, ofreciendo herramientas más flexibles, potentes y fáciles de utilizar sin perder compatibilidad ni control avanzado.&lt;br /&gt;
&lt;br /&gt;
El proyecto continúa evolucionando constantemente con nuevas optimizaciones, formatos y herramientas orientadas tanto a usuarios avanzados como a personas que recién comienzan a trabajar con gráficos dinámicos en SNES.&lt;br /&gt;
&lt;br /&gt;
La intención principal de Dynamic Xtreme es permitir la creación de recursos y sistemas cada vez más complejos, manteniendo al mismo tiempo un workflow más limpio, mantenible y accesible para la comunidad.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21377</id>
		<title>es/Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21377"/>
		<updated>2026-10-25T06:44:33Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo funciona Dynamic Xtreme, desde la preparación de los recursos al instalarlo hasta la carga y el dibujo de una pose durante el juego.&lt;br /&gt;
&lt;br /&gt;
== Qué prepara la instalación ==&lt;br /&gt;
&lt;br /&gt;
Antes de que un sprite pueda usar sus gráficos o una paleta, Dynamic Xtreme tiene que guardarlos en la ROM y preparar la información para encontrarlos. Lo mismo ocurre con cualquier otro recurso dinámico que hayas añadido.&lt;br /&gt;
&lt;br /&gt;
Para hacerlo, la herramienta lee los DynamicInfo, DrawInfo y PaletteEffect. Cada archivo aporta una parte distinta: qué recursos se van a cargar, cómo se dibujan las poses y qué cambios de color se pueden aplicar.&lt;br /&gt;
&lt;br /&gt;
Gracias a esta preparación se generan defines en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permiten utilizar los recursos y ejecutar fácilmente las rutinas necesarias.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: recursos y datos de carga ===&lt;br /&gt;
&lt;br /&gt;
Un DynamicInfo reúne los gráficos de poses, las paletas y los recursos generales que necesita un sprite u otro código. Si incluye gráficos de poses dinámicas, la herramienta los organiza para que puedan cargarse con la distribución de tiles que espera el sistema.&lt;br /&gt;
&lt;br /&gt;
Por cada pose guarda varios datos en tablas separadas. Todas mantienen el mismo orden: la entrada de una pose en una tabla corresponde a esa misma pose en las demás. En la tabla siguiente, &#039;&#039;&#039;N&#039;&#039;&#039; es la cantidad de poses dinámicas instaladas.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || 2 × N || 2 || La cantidad de datos que utiliza cada pose, en bytes. Se utiliza para comprobar si su carga cabe en el presupuesto del frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || N || 1 || Cuántos bloques de 16×16 hay que reservar en VRAM para la pose. No siempre coincide exactamente con los bytes que se copian, porque una pieza incompleta también puede necesitar un bloque de espacio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 × N || 3 || La dirección de los gráficos de cada pose en ROM. Incluye el banco, de modo que el código de carga pueda encontrar su origen completo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 × N || 2; dos valores por pose || Dos tamaños por pose, correspondientes a los dos tramos en que pueden dividirse sus gráficos. La rutina de carga utiliza esos tamaños para repartirlos correctamente en VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 × N || 2 || El desplazamiento en VRAM desde el comienzo del primer tramo hasta el comienzo del segundo. Permite colocar el segundo tramo donde corresponde, aunque el primero termine con una fila incompleta.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas describen todas las poses instaladas, no solo las que están en pantalla. Más adelante, la caché guarda por separado cuáles están cargadas y dónde quedaron.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si se solicita una pose que todavía no está en VRAM, el sistema consulta cuántos bytes necesita cargar, busca espacio para sus bloques y utiliza la dirección y los datos de sus tramos para preparar la carga.&lt;br /&gt;
&lt;br /&gt;
==== Tablas de paletas ====&lt;br /&gt;
&lt;br /&gt;
Las paletas declaradas en los DynamicInfo se reúnen en &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. Si &#039;&#039;&#039;P&#039;&#039;&#039; es la cantidad de entradas de las listas de paletas de los DynamicInfo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; || 2 × P || 2 || ID de cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; || 3 × P || 3 || Dirección de sus colores en ROM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
P cuenta las entradas de las listas, no solo las paletas distintas: una paleta compartida puede aparecer en más de un DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
Las dos listas siguen el orden de las paletas de los DynamicInfo. El define de offset de cada DynamicInfo indica dónde comienza su lista dentro de ellas. Al elegir una versión, el sistema suma ese índice al offset y obtiene tanto el ID como la dirección de los colores elegidos.&lt;br /&gt;
&lt;br /&gt;
El ID permite reconocer y compartir una paleta; la dirección permite cargarla. No son el número de paleta de pantalla: una misma paleta instalada puede terminar, por ejemplo, en la paleta 9 o en la C según la asignación.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y defines ====&lt;br /&gt;
&lt;br /&gt;
Los archivos declarados en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; se guardan en ROM. Su dirección y la cantidad de bytes que ocupan pueden consultarse mediante los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Por ejemplo, para &amp;lt;code&amp;gt;my_resource.bin&amp;lt;/code&amp;gt; se generan:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt;: dirección del recurso en ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt;: cantidad de bytes que ocupa.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt;: ID del recurso.&lt;br /&gt;
&lt;br /&gt;
El nombre se normaliza en PascalCase: se eliminan espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: datos y rutinas de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El DrawInfo describe cómo está formada una pose: qué tiles tiene, dónde se coloca cada uno, qué tamaño utiliza y cómo cambia al voltearse.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, Dynamic Xtreme genera rutinas de dibujo optimizadas según los parámetros que utilizan los tiles. Tiene en cuenta, por ejemplo, si necesitan desplazamientos X e Y, si comparten el mismo tamaño, si utilizan propiedades comunes y si requieren volteos.&lt;br /&gt;
&lt;br /&gt;
De esta forma, la rutina realiza el trabajo que necesita ese dibujo sin añadir el manejo de opciones que no utiliza. Varias poses pueden compartirla si necesitan el mismo tratamiento; eso no significa que compartan también sus gráficos o su ID.&lt;br /&gt;
&lt;br /&gt;
La relación entre una pose y su dibujo se guarda en estas tablas. &#039;&#039;&#039;D&#039;&#039;&#039; es la cantidad de poses de dibujo y &#039;&#039;&#039;R&#039;&#039;&#039; la cantidad de rutinas generadas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || 2 × D || 2 || Dónde comienzan los datos de la pose dentro de las tablas de su rutina de dibujo. Así se localizan sus tiles y desplazamientos sin recorrer las poses anteriores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || D || 1 || La cantidad de tiles de la pose menos uno. Una pose de cuatro tiles guarda 3; la rutina utiliza ese valor para recorrer sus piezas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || D || 1 || Qué rutina de dibujo utiliza cada pose. Las poses con características compatibles pueden apuntar al mismo ID de rutina.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || 3 × R || 3 por rutina || Las direcciones de las rutinas de dibujo. El ID de rutina permite encontrar aquí el código que debe ejecutarse.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada rutina tiene, además, las tablas que necesitan sus poses. Aquí &#039;&#039;&#039;T&#039;&#039;&#039; es la cantidad de entradas de cada tabla de la rutina:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos !! Bytes totales !! Bytes por valor !! Qué describen&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || T, si se genera || 1 || Los números de tile que forman la pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || T, si se genera || 1 || Las propiedades de cada pieza, como los volteos y su prioridad respecto a las capas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || T por tabla, si se genera || 1 || La posición de cada tile respecto al punto de origen de la pose.&lt;br /&gt;
|-&lt;br /&gt;
| Tablas de desplazamientos para los volteos || T por tabla, si se genera || 1 || Las posiciones que deben utilizarse al voltear la pose cuando necesita una distribución distinta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || T, si se genera || 1 || El tamaño de cada tile: 8×8 o 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
No todas estas tablas tienen que aparecer en todas las rutinas. Si un dato es igual para todas las piezas o puede obtenerse de un valor común, la herramienta puede generar una rutina que lo utilice directamente.&lt;br /&gt;
&lt;br /&gt;
La optimización se hace durante la instalación. Si todos los tiles tienen el mismo tamaño, por ejemplo, la rutina puede utilizar ese valor común sin leer un tamaño distinto para cada pieza.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: datos de los efectos ===&lt;br /&gt;
&lt;br /&gt;
Un archivo PaletteEffect contiene una lista de cambios de color. La instalación les asigna IDs y guarda sus datos en &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Como en las tablas de poses, los datos de cada efecto mantienen la misma posición en las distintas listas. Los IDs de efectos comienzan en 1; el ID 0 se utiliza para indicar que no hay efecto global. En la tabla, &#039;&#039;&#039;E&#039;&#039;&#039; es la cantidad de efectos instalados; el conjunto ocupa &#039;&#039;&#039;2 + 7 × E bytes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parte de la tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || 2 || 2 || La cantidad de efectos instalados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || E || 1 || El tipo de cada efecto, por ejemplo &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Indica qué cálculo debe realizarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || E por tabla; 3 × E entre las tres || 1 por tabla || Los valores de los canales que utiliza el efecto. En una transición, estos tres bytes guardan la dirección de la paleta de destino, no valores de canales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || E por tabla; 3 × E entre las tres || 1 por tabla || Cuánto se aplica el cambio en cada componente. Van de 0 a 127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Si el efecto es una transición hacia otra paleta, la herramienta también prepara esa paleta. Convierte sus colores al formato RGB o HSL que necesita la transición y los guarda en ROM. Durante el juego se puede utilizar ese destino sin tener que convertirlo de nuevo en cada llamada.&lt;br /&gt;
&lt;br /&gt;
Estas paletas de transición son distintas de las paletas normales que se cargan a CGRAM: contienen tres componentes por color y se utilizan para calcular el efecto.&lt;br /&gt;
&lt;br /&gt;
=== Cómo encuentra el código los recursos instalados ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; publica los IDs, direcciones, tamaños y offsets que necesitan los recursos. Por ejemplo, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifica una pose y &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifica el primer efecto de un archivo.&lt;br /&gt;
&lt;br /&gt;
Los nombres se normalizan en PascalCase: se eliminan separadores como espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra. &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, por ejemplo, pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También se genera &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, que guarda las direcciones de los bloques donde se insertaron los recursos. Cada dirección ocupa 3 bytes y se añade un valor final &amp;lt;code&amp;gt;$FFFFFF&amp;lt;/code&amp;gt; de otros 3 bytes. Para B bloques, ocupa &amp;lt;code&amp;gt;3 × (B + 1)&amp;lt;/code&amp;gt; bytes. La herramienta utiliza esa información para localizar los datos de una instalación anterior al reinstalar.&lt;br /&gt;
&lt;br /&gt;
Una reinstalación puede cambiar IDs y direcciones. Por eso hay que volver a insertar los sprites, bloques y códigos UberASM que utilizan los defines generados.&lt;br /&gt;
&lt;br /&gt;
== El trabajo de cada frame ==&lt;br /&gt;
&lt;br /&gt;
En la lógica principal se ejecutan el jugador, los sprites y los demás códigos del modo de juego. Los que utilizan Dynamic Xtreme solicitan las poses y paletas que necesitan, preparan los efectos locales y llaman a las rutinas de dibujo. Las cargas que se aceptan quedan anotadas para transferir sus datos durante NMI.&lt;br /&gt;
&lt;br /&gt;
Al terminar esa lógica, el código de game mode de Dynamic Xtreme realiza las tareas que correspondan a las opciones habilitadas: prepara las actualizaciones de VRAM de la optimización de Kevin, mantiene el estado de las paletas y calcula los efectos globales pendientes.&lt;br /&gt;
&lt;br /&gt;
Después, durante NMI, se ejecutan las transferencias preparadas: los gráficos se copian a VRAM y los colores a CGRAM. También se reinicia el contador de datos y se actualizan los relojes del sistema para el siguiente ciclo de trabajo.&lt;br /&gt;
&lt;br /&gt;
El orden que seguiremos para explicarlo es, por tanto, &#039;&#039;&#039;lógica principal → tareas al terminar el game mode → transferencias durante NMI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Lógica principal ===&lt;br /&gt;
&lt;br /&gt;
Cada recurso decide qué necesita. Un sprite puede cambiar de pose, una animación puede pedir nuevos gráficos y un código UberASM puede cargar una paleta o seleccionar un efecto.&lt;br /&gt;
&lt;br /&gt;
Si la pose solicitada ya está cargada, Dynamic Xtreme actualiza su tiempo de último uso para protegerla del reemplazo y no vuelve a cargar sus gráficos. Si no está cargada, comprueba el presupuesto de datos del frame y busca espacio disponible en VRAM antes de preparar su carga.&lt;br /&gt;
&lt;br /&gt;
El dibujo también se prepara en esta parte: las rutinas escriben en los buffers OAM la posición, los tiles y las propiedades de las piezas que se mostrarán.&lt;br /&gt;
&lt;br /&gt;
Una solicitud puede rechazarse, por ejemplo si no queda presupuesto para sus datos. El recurso que la pidió debe comprobar el resultado y decidir si conserva lo anterior o vuelve a intentarlo después. Una carga rechazada no queda guardada automáticamente para otro frame.&lt;br /&gt;
&lt;br /&gt;
=== Tareas de game mode ===&lt;br /&gt;
&lt;br /&gt;
En esta parte se realizan las siguientes tareas, según las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antes de ejecutar la lógica del juego:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitado &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;, se ejecuta la rutina del control aquí en lugar de hacerlo en NMI.&lt;br /&gt;
# Se comprueba si Dynamic Xtreme debe funcionar en el game mode actual. Si no debe hacerlo, se reinician sus variables. Esto ocurre cada frame que se permanezca en un modo no permitido.&lt;br /&gt;
&lt;br /&gt;
Después se ejecuta la lógica normal del juego, incluidos los sprites y los códigos que solicitan cargas o cambios de paleta.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cuando termina esa lógica:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitada la optimización de VRAM de Kevin, se ajustan los destinos de las actualizaciones de Lunar Magic antes de que se transfieran.&lt;br /&gt;
# Se ponen en 0 los indicadores de actualización de las paletas y se resta 1 a sus temporizadores de protección si todavía son mayores que 0. Esta parte se omite durante la pausa y en los modos no permitidos.&lt;br /&gt;
# Se aplican los efectos globales a las paletas que necesitan actualizarse y se preparan las transferencias de sus colores. Esta parte también se omite si la comprobación anterior impide continuar.&lt;br /&gt;
&lt;br /&gt;
Las copias a VRAM y CGRAM se realizan después, durante NMI. Aquí se deja preparado lo que se va a copiar.&lt;br /&gt;
&lt;br /&gt;
=== Transferencias durante NMI ===&lt;br /&gt;
&lt;br /&gt;
NMI es una interrupción que SNES puede generar al comenzar VBlank, después de dibujar la parte visible de la pantalla. El juego aprovecha ese intervalo para actualizar gráficos, colores y otros datos de video.&lt;br /&gt;
&lt;br /&gt;
En los modos permitidos, la rutina de Dynamic Xtreme reinicia &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; y actualiza sus relojes. Después ejecuta las transferencias de gráficos pendientes y luego las de paletas. Si corresponde, también actualiza el color 0,0 preparado por el sistema de efectos.&lt;br /&gt;
&lt;br /&gt;
Para realizar las copias se utiliza DMA. NMI lee cada carga de las listas, configura desde dónde se copiarán los datos, cuántos bytes se copiarán y dónde se colocarán, y ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
El tiempo de VBlank es limitado y SMW también lo necesita para sus actualizaciones de pantalla. Para limitar la cantidad de datos enviados en un frame y evitar flickering, Dynamic Xtreme utiliza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, que cuenta los bytes de las cargas solicitadas, y &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, que establece el límite permitido. Antes de aceptar una carga normal, se comprueba que sus bytes no hagan superar ese límite.&lt;br /&gt;
&lt;br /&gt;
==== Las listas de transferencias ====&lt;br /&gt;
&lt;br /&gt;
Cada transferencia guarda el origen de los datos, su banco, la cantidad de bytes y el destino en VRAM o CGRAM.&lt;br /&gt;
&lt;br /&gt;
Al realizar las copias, NMI recorre las listas desde la última entrada hacia la primera y después las vacía. Esto no borra los gráficos o colores cargados: permanecen en su destino hasta que otro código los cambie.&lt;br /&gt;
&lt;br /&gt;
La lista de VRAM utiliza 0 cuando no tiene entradas. La de CGRAM utiliza &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, porque guarda el índice de la última entrada en lugar de guardar directamente su cantidad.&lt;br /&gt;
&lt;br /&gt;
Si dos códigos escriben sobre el mismo destino, deben coordinar sus cargas. El orden de las solicitudes no debe utilizarse como sustituto de decidir qué recurso puede ocupar cada espacio.&lt;br /&gt;
&lt;br /&gt;
Normalmente, el recurso se lee desde ROM. Si el recurso se encuentra en un buffer en RAM, el usuario debe conservar su contenido hasta que NMI realice la transferencia. Por ejemplo, si prepara una paleta en RAM, no debe modificar ni reutilizar ese buffer antes de que se copie. La lista guarda su dirección, no una copia de sus datos; Dynamic Xtreme no protege el buffer contra cambios realizados por otros códigos.&lt;br /&gt;
&lt;br /&gt;
==== Presupuesto de datos ====&lt;br /&gt;
&lt;br /&gt;
Las macros de transferencia, como &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt;, comprueban cuántos bytes se han solicitado mediante &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;. Si al añadir la nueva carga se supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, la rechazan. Si la aceptan, suman sus bytes al contador.&lt;br /&gt;
&lt;br /&gt;
El límite predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Su objetivo es evitar flickering por enviar demasiados datos en un mismo frame. Es un límite de cantidad de datos, no una medida exacta del tiempo que tarda cada transferencia.&lt;br /&gt;
&lt;br /&gt;
Estas macros tienen variantes como &amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ForcedTransferToCGRAM()&amp;lt;/code&amp;gt;, que aceptan la carga sin comprobar si supera el límite. Sus bytes también se suman a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, por lo que reducen lo que queda disponible para las siguientes cargas normales. Se utilizan para cargas prioritarias, como las del jugador; usarlas no evita el flickering si se solicita una cantidad excesiva de datos.&lt;br /&gt;
&lt;br /&gt;
==== Los dos relojes ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_Timer: protección de las solicitudes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza cuando se ejecuta la parte de NMI de Dynamic Xtreme. Además de medir cuánto lleva una pose sin utilizarse, sirve para evitar que un recurso repita sus solicitudes antes de que se procesen las anteriores.&lt;br /&gt;
&lt;br /&gt;
No siempre hay un ciclo de lógica por cada ejecución completa de NMI. Durante slowdown, SMW puede ejecutar una versión reducida de NMI, y puede haber dos ciclos de lógica sin que entre ellos se hayan procesado las listas de transferencias de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Sin una protección, un recurso podría añadir otra vez sus cargas a esas listas. Las solicitudes repetidas ocuparían más espacio y podrían provocar flickering.&lt;br /&gt;
&lt;br /&gt;
Para evitarlo, las rutinas con esta protección comparan &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; con un valor guardado por el recurso, normalmente llamado &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt;. Si coinciden, el recurso ya hizo su intento con ese valor del reloj y no debe añadir de nuevo las cargas. Si son distintos, guarda el valor actual y puede realizar la nueva solicitud.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; continúa avanzando durante la pausa cuando se ejecuta esa parte de NMI.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_SyncTimer: animaciones sincronizadas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
La función principal de &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; es dar a los sprites un reloj común para sus animaciones. Por ejemplo, varios sprites que utilizan las mismas poses pueden calcular con este reloj qué pose les corresponde cada cuatro frames.&lt;br /&gt;
&lt;br /&gt;
Así todos cambian al mismo tiempo y solicitan la misma pose. La primera solicitud puede necesitar cargarla; las demás la reutilizan sin programar otra carga de sus gráficos. Esto ahorra transferencias DMA y datos enviados por frame.&lt;br /&gt;
&lt;br /&gt;
Si cada sprite llevara un reloj independiente, podrían terminar usando poses distintas de la misma animación al mismo tiempo y necesitar más cargas y espacio de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; se detiene durante la pausa y cuando se congela la acción, para que las animaciones sincronizadas también se detengan.&lt;br /&gt;
&lt;br /&gt;
== Carga de gráficos: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; guarda en RAM una lista de solicitudes de carga. Durante NMI se recorren esas solicitudes y se copian sus datos a VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Variables de la lista ===&lt;br /&gt;
&lt;br /&gt;
En esta tabla, &#039;&#039;&#039;V&#039;&#039;&#039; es el valor de &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt;: 64 por defecto. Las cuatro tablas de solicitudes reservan V bytes cada una; con entradas de 2 bytes, ese valor deja espacio para 32 solicitudes. Junto con el contador, reservan &amp;lt;code&amp;gt;1 + 4 × V&amp;lt;/code&amp;gt; bytes: 257 por defecto.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de solicitudes pendientes. El valor 0 indica que la lista está vacía.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Dirección de origen de cada solicitud, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 reservados; banco de 1 byte || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Cantidad de bytes que se copiarán.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Dirección de destino en VRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las tablas mantienen el mismo orden: la primera entrada de cada tabla pertenece a la primera solicitud, la segunda a la segunda, etc. Cada entrada de estas tablas ocupa 2 bytes, por lo que se avanza con desplazamientos de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt;, etc.&lt;br /&gt;
&lt;br /&gt;
Estos nombres representan direcciones de RAM calculadas en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus direcciones pueden cambiar según la configuración y las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
=== Añadir una solicitud ===&lt;br /&gt;
&lt;br /&gt;
La macro &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; realiza los siguientes pasos:&lt;br /&gt;
&lt;br /&gt;
# Calcula cuántos bytes habría en total al añadir la nueva carga a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Compara el resultado con &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;. Si lo supera, devuelve el carry desactivado y no añade la solicitud.&lt;br /&gt;
# Utiliza &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para encontrar la siguiente entrada y aumenta ese contador en 1.&lt;br /&gt;
# Guarda el origen, banco, cantidad de bytes y destino en las tablas.&lt;br /&gt;
# Actualiza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; con los bytes de la carga y devuelve el carry activado.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; guarda los mismos datos, pero no comprueba el límite de bytes. Las variantes &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; facilitan obtener el origen desde una dirección completa o desde los defines de un recurso.&lt;br /&gt;
&lt;br /&gt;
Añadir una solicitud no copia los gráficos inmediatamente: deja la información preparada para NMI.&lt;br /&gt;
&lt;br /&gt;
=== Ejecutar las solicitudes durante NMI ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Lee &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;. Si es 0, termina porque no hay solicitudes.&lt;br /&gt;
# Calcula el desplazamiento de la última entrada: &amp;lt;code&amp;gt;(Length - 1) × 2&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Lee su origen, banco y cantidad de bytes, y los coloca en los registros de DMA.&lt;br /&gt;
# Escribe el destino de VRAM en &amp;lt;code&amp;gt;$2116-$2117&amp;lt;/code&amp;gt; e inicia la transferencia mediante &amp;lt;code&amp;gt;$420B&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Retrocede 2 bytes para procesar la solicitud anterior. Repite hasta completar la primera.&lt;br /&gt;
# Escribe 0 en &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para indicar que la lista está vacía.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;La lista se ejecuta del final al inicio.&#039;&#039;&#039; No hace falta borrar todos sus datos al terminar: al quedar su largo en 0, la próxima solicitud volverá a utilizar la primera entrada.&lt;br /&gt;
&lt;br /&gt;
=== Animaciones con un destino fijo ===&lt;br /&gt;
&lt;br /&gt;
El código de una animación debe:&lt;br /&gt;
&lt;br /&gt;
# Elegir la imagen que corresponde al paso actual.&lt;br /&gt;
# Calcular su dirección de origen.&lt;br /&gt;
# Solicitar la copia al destino de VRAM de la animación.&lt;br /&gt;
# Comprobar el carry. Si se rechaza la carga, conservar la imagen anterior y volver a intentarlo.&lt;br /&gt;
&lt;br /&gt;
El destino puede ser siempre el mismo. Lo que cambia es la imagen que se copia allí; la lista de transferencias no decide cuándo debe avanzar la animación.&lt;br /&gt;
&lt;br /&gt;
Puedes ver un código completo en [[es/Dynamic_Xtreme_UberASM_guide#Crear_animaciones_de_gráficos|Crear animaciones de gráficos de la guía de UberASM]].&lt;br /&gt;
&lt;br /&gt;
=== Carga de una pose dinámica ===&lt;br /&gt;
&lt;br /&gt;
La carga de una pose utiliza la caché para no repetir transferencias de gráficos que ya están disponibles:&lt;br /&gt;
&lt;br /&gt;
# Busca el ID en la tabla hash.&lt;br /&gt;
# Si ya está registrado, actualiza su tiempo de uso y no añade otra carga.&lt;br /&gt;
# Si no está, comprueba la cantidad de bytes y busca un espacio adecuado en el mapa de VRAM.&lt;br /&gt;
# Elige qué poses pueden reemplazarse, teniendo en cuenta su tiempo sin uso y el espacio que necesita la nueva.&lt;br /&gt;
# Actualiza las tablas de la caché y el mapa.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; divide los datos de la pose en las transferencias necesarias.&lt;br /&gt;
# NMI ejecuta esas transferencias.&lt;br /&gt;
&lt;br /&gt;
Cada paso se desarrolla en [[#Sprites_dinámicos:_DynamicPoses|Sprites dinámicos: DynamicPoses]], incluyendo la búsqueda por hash, el mapa, la política de reemplazo y la división de la carga en filas.&lt;br /&gt;
&lt;br /&gt;
== Carga y asignación de paletas: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
El sistema distingue dos valores:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID de paleta:&#039;&#039;&#039; identifica los colores guardados en ROM.&lt;br /&gt;
* &#039;&#039;&#039;Color de destino:&#039;&#039;&#039; indica desde qué color de la paleta de colores de CGRAM se colocarán los colores que se carguen. Por ejemplo, &amp;lt;code&amp;gt;$91&amp;lt;/code&amp;gt; comienza en el color 1 de la paleta 9.&lt;br /&gt;
&lt;br /&gt;
La asignación automática permite compartir colores entre sprites sin exigir un destino fijo para cada uno.&lt;br /&gt;
&lt;br /&gt;
=== Lista de cargas a CGRAM ===&lt;br /&gt;
&lt;br /&gt;
En esta tabla, &#039;&#039;&#039;C&#039;&#039;&#039; es &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt;: 64 por defecto. El conjunto reserva &amp;lt;code&amp;gt;1 + 7 × C&amp;lt;/code&amp;gt; bytes, es decir, 449 con ese valor. Aunque &amp;lt;code&amp;gt;SourceBNK&amp;lt;/code&amp;gt; reserva 2 × C bytes, el código utiliza un byte de banco por solicitud.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Índice de la última solicitud pendiente. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; indica una lista vacía; 0 indica que hay una solicitud.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || 2 × C; 128 por defecto || 2 || Dirección de origen, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || 2 × C; 128 reservados por defecto || 1 utilizado por solicitud || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || 2 × C; 128 por defecto || 2 || Cantidad de bytes que se copiarán. Cada color ocupa 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || C; 64 por defecto || 1 || Primer color de destino en CGRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Durante NMI, &amp;lt;code&amp;gt;CGRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Comienza por la última solicitud pendiente.&lt;br /&gt;
# Configura DMA con el origen y la cantidad de bytes de esa solicitud.&lt;br /&gt;
# Selecciona el primer color mediante &amp;lt;code&amp;gt;$2121&amp;lt;/code&amp;gt; y realiza la copia.&lt;br /&gt;
# Continúa con las solicitudes anteriores.&lt;br /&gt;
# Al terminar, escribe &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; también actualizan las copias de colores y el estado de efectos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Sin efecto global:&#039;&#039;&#039; solicitan la carga y actualizan los buffers de SMW. Así el juego no vuelve a utilizar colores anteriores durante la animación de victoria del goal.&lt;br /&gt;
* &#039;&#039;&#039;Con efecto global:&#039;&#039;&#039; guardan los colores originales y preparan el estado necesario para aplicarles el efecto antes de enviarlos a CGRAM.&lt;br /&gt;
&lt;br /&gt;
=== Asignación automática ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 32 || 2 || Guarda el ID asignado a cada destino. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre y &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; una reservada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 16 || 1 || Protege cada destino del reemplazo automático mientras está en uso.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta de sprites || Indica qué paletas de sprites están asignadas con efecto global habilitado. Esta condición también se compara al compartir una asignación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue este orden:&lt;br /&gt;
&lt;br /&gt;
# Reutilizar una asignación con el mismo ID y una condición de efecto compatible.&lt;br /&gt;
# Si no existe, utilizar una entrada libre.&lt;br /&gt;
# Si no hay entradas libres, reemplazar una que no esté reservada y cuyo temporizador sea 0.&lt;br /&gt;
# Si no encuentra ninguna, indicar que la asignación falló.&lt;br /&gt;
&lt;br /&gt;
Mientras el recurso utiliza la paleta, mantiene su temporizador en 2. Llegar a 0 no borra los colores: la asignación puede reutilizarse si otro recurso todavía no la reemplazó.&lt;br /&gt;
&lt;br /&gt;
=== Asignación manual y versión ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Manual con carga:&#039;&#039;&#039; el código elige el destino y solicita sus colores.&lt;br /&gt;
* &#039;&#039;&#039;Manual sin carga:&#039;&#039;&#039; el código elige el destino y utiliza los colores que ya estaban preparados.&lt;br /&gt;
* &#039;&#039;&#039;Versión:&#039;&#039;&#039; selecciona una entrada de la lista de paletas del DynamicInfo. La última versión procesada permite comprobar si esa selección cambió.&lt;br /&gt;
&lt;br /&gt;
Dos recursos que elijan el mismo destino con colores distintos deben coordinarse. Mantener la protección de una paleta no significa volver a cargar sus colores.&lt;br /&gt;
&lt;br /&gt;
== Dibujo de poses: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
El dibujo prepara las piezas de una pose en OAM: qué tiles se muestran, dónde se colocan y qué propiedades utilizan. Los datos gráficos deben estar en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Pasos del dibujo ===&lt;br /&gt;
&lt;br /&gt;
# Busca la rutina y los datos de la pose mediante &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Obtiene la cantidad de piezas desde &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Calcula la posición de cada tile usando la posición del sprite, sus desplazamientos y los volteos que correspondan.&lt;br /&gt;
# Comprueba si la pieza puede verse y si queda espacio de OAM.&lt;br /&gt;
# Escribe su posición, número de tile, propiedades y tamaño en los buffers OAM.&lt;br /&gt;
&lt;br /&gt;
El número de tile depende del dibujo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Cómo se obtiene el tile&lt;br /&gt;
|-&lt;br /&gt;
| Pose dinámica || Se ajusta al lugar de VRAM donde quedaron cargados sus gráficos.&lt;br /&gt;
|-&lt;br /&gt;
| Pose estática || Se utiliza su número de tile fijo.&lt;br /&gt;
|-&lt;br /&gt;
| Pose que utiliza un tile común || El código debe preparar &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; antes de llamar al dibujo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Prioridad y espacio disponible ===&lt;br /&gt;
&lt;br /&gt;
* En &#039;&#039;&#039;LoROM&#039;&#039;&#039;, el sistema lleva su propio control de entradas OAM disponibles.&lt;br /&gt;
* En &#039;&#039;&#039;SA-1&#039;&#039;&#039;, utiliza la integración con MaxTile.&lt;br /&gt;
* La &#039;&#039;&#039;prioridad de dibujo&#039;&#039;&#039; organiza las piezas de sprites. No es la misma propiedad que determina si un tile queda delante o detrás de las capas.&lt;br /&gt;
* Los &#039;&#039;&#039;límites por línea de pantalla&#039;&#039;&#039; de SNES siguen existiendo. Tener una pose cargada no garantiza que puedan verse todas sus piezas.&lt;br /&gt;
&lt;br /&gt;
== Jugador y Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
El jugador original tiene rutinas propias para elegir y cargar las piezas de sus poses. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; permite integrar ese trabajo con las cargas de Dynamic Xtreme y cambiar el origen de sus gráficos y paletas.&lt;br /&gt;
&lt;br /&gt;
Con el formato original, el juego sigue eligiendo las piezas de la pose. La rutina obtiene sus direcciones desde el origen configurado y compara esas direcciones con las anteriores para cargar las que hayan cambiado.&lt;br /&gt;
&lt;br /&gt;
Estas cargas utilizan transferencias forzadas y sus bytes también cuentan para las solicitudes normales posteriores. Así conservan su prioridad sin quedar fuera de la contabilidad del sistema.&lt;br /&gt;
&lt;br /&gt;
La paleta del jugador tiene un tratamiento especial: combina colores y selecciones del propio juego con el origen personalizado. No funciona simplemente como sustituir una paleta completa de un sprite cualquiera.&lt;br /&gt;
&lt;br /&gt;
El soporte para jugadores personalizados permite que otros sistemas administren de otra forma sus poses y dibujo. No convierte automáticamente cualquier spritesheet al formato del jugador original.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi también carga sus gráficos por piezas. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; permite cambiar su origen manteniendo la organización que esperan sus rutinas.&lt;br /&gt;
&lt;br /&gt;
El código calcula qué partes necesita y prepara sus cargas a los destinos correspondientes de VRAM. Como las del jugador, estas cargas tienen un tratamiento prioritario.&lt;br /&gt;
&lt;br /&gt;
Esta opción necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad. No permite evitar un conflicto del sistema del jugador habilitando únicamente las funciones de Yoshi.&lt;br /&gt;
&lt;br /&gt;
== Memoria y optimizaciones ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW mantiene en RAM gráficos originales del jugador, Yoshi y ciertas animaciones. En ROMs sin SA-1, esta opción adapta las cargas para leer esos datos desde ROM.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aprovecha la RAM recuperada para sus variables internas. No es un espacio que quede libre para que cualquier otro código escriba encima.&lt;br /&gt;
&lt;br /&gt;
SA-1 utiliza otras direcciones y desactiva esta opción. Los rangos están en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
Esta opción mueve el procesamiento del control desde NMI a la parte de game mode. El objetivo es dejar más tiempo para las actualizaciones de pantalla, no añadir un frame de retraso ni cambiar los botones que recibe el juego.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
El color fijo se utiliza en las mezclas de color de la consola. Para actualizarlo, el juego prepara sus componentes y los envía al registro correspondiente.&lt;br /&gt;
&lt;br /&gt;
La optimización reemplaza esa preparación por una secuencia más corta. El color sigue enviándose a la consola, pero necesita menos trabajo durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic utiliza listas llamadas stripe images para actualizar partes de los mapas de tiles. Esas listas incluyen tanto los datos como la información sobre sus destinos.&lt;br /&gt;
&lt;br /&gt;
La versión integrada de la optimización de Kevin prepara fuera de NMI parte del ajuste de esos destinos. Así deja menos trabajo de preparación para el momento de la transferencia.&lt;br /&gt;
&lt;br /&gt;
Esta opción sustituye el uso del parche original por separado. Además, no debe desinstalarse después de instalarla; hay que tenerlo en cuenta antes de activarla.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
La barra de estado original actualiza zonas concretas de VRAM. Esta opción prepara sus transferencias de forma más directa, reduciendo la configuración de DMA que necesita hacer durante NMI.&lt;br /&gt;
&lt;br /&gt;
No añade una barra nueva. Modifica la actualización de la original y, por eso, entra en conflicto con recursos que la reemplazan, modifican o eliminan.&lt;br /&gt;
&lt;br /&gt;
== Sprites dinámicos: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
El sistema funciona como una &#039;&#039;&#039;caché de poses en VRAM&#039;&#039;&#039;. No reserva una copia de los gráficos para cada sprite: guarda la pose y permite que la reutilicen todos los recursos que la necesiten.&lt;br /&gt;
&lt;br /&gt;
* Una pose se carga una sola vez mientras permanezca en la caché.&lt;br /&gt;
* Las siguientes solicitudes actualizan su tiempo de último uso, sin añadir otra carga de sus gráficos.&lt;br /&gt;
* La pose no se borra cuando un recurso deja de utilizarla. Permanece allí hasta que se necesite su espacio y se elija reemplazarla.&lt;br /&gt;
* Si fue reemplazada y vuelve a solicitarse, tendrá que cargarse otra vez.&lt;br /&gt;
&lt;br /&gt;
La elección no depende de cuánto tiempo lleva la pose desde que se cargó, sino de &#039;&#039;&#039;cuánto tiempo lleva sin utilizarse&#039;&#039;&#039; y de si su espacio sirve para la pose nueva.&lt;br /&gt;
&lt;br /&gt;
=== Tres valores distintos ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Qué identifica&lt;br /&gt;
|-&lt;br /&gt;
| ID de pose || La pose instalada. Tiene 16 bits y permite consultar sus datos en ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Índice de la tabla hash || La entrada de RAM donde se registró la pose. Va de 0 a 127.&lt;br /&gt;
|-&lt;br /&gt;
| Bloque de VRAM || ID de una de las 128 posiciones para tiles de 16×16 que caben en el espacio de VRAM de sprites. Se numeran de izquierda a derecha y de arriba abajo, desde 0 hasta 127. Para una pose que ocupa varios bloques, se guarda el ID de su primer bloque.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
El índice de la tabla hash y el bloque de VRAM no tienen por qué coincidir. Una entrada de la tabla puede registrar una pose que empieza en cualquier bloque permitido.&lt;br /&gt;
&lt;br /&gt;
=== Tablas de las poses registradas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de poses registradas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 || 1 || Cantidad de poses registradas para cada hash.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 256 || 2 || ID completo de la pose de cada entrada. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Bloque de VRAM donde comienza cada pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 256 || 2 || Valor de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; de su último uso.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas ocupan &#039;&#039;&#039;769 bytes&#039;&#039;&#039; en RAM. Guardan las poses registradas durante el juego; las tablas generadas desde el DynamicInfo describen, en cambio, todas las poses instaladas.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se busca una pose ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;DynamicPoseHashmap_FindPose&amp;lt;/code&amp;gt; utiliza una tabla hash de 128 entradas. El hash permite elegir dónde empezar a buscar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hash = ID de pose AND $007F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dos IDs diferentes pueden tener el mismo hash. Por ejemplo, &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; producen &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;. Por eso el hash no basta para confirmar que la pose está cargada: también se compara el ID completo.&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue estos pasos:&lt;br /&gt;
&lt;br /&gt;
# Guarda el ID solicitado y calcula su hash.&lt;br /&gt;
# Si &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; es 0, no hay poses registradas y la búsqueda termina.&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize[hash]&amp;lt;/code&amp;gt;. Si es 0, ninguna pose registrada tiene ese hash y también termina.&lt;br /&gt;
# Comienza por la entrada cuyo índice coincide con el hash.&lt;br /&gt;
# Lee el ID de esa entrada. Si coincide con el solicitado, encontró la pose.&lt;br /&gt;
# Si no coincide, continúa con la siguiente entrada de la secuencia de búsqueda.&lt;br /&gt;
&lt;br /&gt;
La secuencia avanza &#039;&#039;&#039;15 entradas por intento&#039;&#039;&#039; y vuelve al comienzo al superar 127:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
siguiente índice = (índice actual + 15) AND $7F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Con 128 entradas, ese paso permite visitar todas las posiciones antes de repetir una. Para el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, el comienzo de la secuencia es:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$05 → $14 → $23 → $32 → $41 → ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== El contador de poses de cada hash ====&lt;br /&gt;
&lt;br /&gt;
Cada hash tiene su propio contador en &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt;. Por ejemplo, si hay dos poses registradas cuyo ID produce el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, la entrada &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize+$05&amp;lt;/code&amp;gt; contiene 2.&lt;br /&gt;
&lt;br /&gt;
Ese número indica &#039;&#039;&#039;cuántas poses con ese hash existen&#039;&#039;&#039;, no cuántas posiciones hay que recorrer. La búsqueda utiliza una copia temporal del contador:&lt;br /&gt;
&lt;br /&gt;
# Comienza con la cantidad de poses registrada para el hash solicitado.&lt;br /&gt;
# Recorre las posiciones de la secuencia hasta encontrar el ID solicitado o haber comprobado esa cantidad de poses con el mismo hash.&lt;br /&gt;
# Cada vez que encuentra una pose con ese hash, pero con otro ID, resta 1 al contador temporal.&lt;br /&gt;
# Las posiciones libres y las poses de otros hashes no descuentan nada: continúa buscando.&lt;br /&gt;
# Si el contador temporal llega a 0 sin encontrar el ID, la pose solicitada no está registrada y la búsqueda termina.&lt;br /&gt;
&lt;br /&gt;
El contador de &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; no se modifica durante esta búsqueda. Solo se actualiza al añadir o retirar poses de la caché.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, se busca &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt;, que produce el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, y el contador de ese hash vale 2:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Posición visitada !! ID guardado !! Hash del ID !! Poses del hash $05 que faltan por comprobar&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 1: tiene el mismo hash, pero no es el ID solicitado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0014&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || 1: es otro hash, así que no se descuenta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$23&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 0: ya se comprobaron las dos poses con ese hash. &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt; no está registrada.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Lo habitual es que haya una o dos poses por hash. Esto permite resolver la búsqueda con pocas comprobaciones y un coste normalmente cercano a &amp;lt;code&amp;gt;O(1)&amp;lt;/code&amp;gt;. No significa que siempre se visiten solo una o dos posiciones: puede haber entradas de otros hashes entre ellas. Con muchas colisiones, el recorrido puede ser más largo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Una entrada libre no termina la búsqueda.&#039;&#039;&#039; Puede haber quedado vacía al reemplazar una pose y existir otra del mismo hash más adelante. El contador permite saber cuándo ya se comprobaron todas las poses de ese hash, incluso si hay huecos entre ellas.&lt;br /&gt;
&lt;br /&gt;
==== Cuando encuentra la pose ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Obtiene el índice de la entrada encontrada.&lt;br /&gt;
# Escribe el valor actual de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; para esa entrada.&lt;br /&gt;
# Devuelve el éxito de la solicitud, sin volver a programar la carga de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
Así todos los recursos que solicitan ese ID utilizan la misma pose y la mantienen protegida. No importa si el recurso es un sprite normal, cluster, extended u otro código que utiliza el sistema.&lt;br /&gt;
&lt;br /&gt;
Esto también evita duplicar una carga dentro del mismo ciclo: cuando la primera solicitud se acepta, la pose ya queda registrada aunque la transferencia física se vaya a realizar durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== Cuando la pose no está registrada ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt; continúa con la preparación de una carga nueva:&lt;br /&gt;
&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; y calcula &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend + PoseSize&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, termina con fallo, sin cambiar las poses existentes.&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; para saber cuántos bloques necesita.&lt;br /&gt;
# Llama a &amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; para buscar un espacio adecuado.&lt;br /&gt;
# Si no existe un espacio utilizable, termina con fallo.&lt;br /&gt;
# Retira del mapa y de la tabla hash las poses que ocupen el espacio elegido.&lt;br /&gt;
# Busca una entrada libre de la tabla hash y registra la pose nueva.&lt;br /&gt;
# Actualiza el mapa de VRAM y el contador de datos del frame.&lt;br /&gt;
# Llama a &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; para añadir las transferencias.&lt;br /&gt;
&lt;br /&gt;
El presupuesto se comprueba antes de reemplazar poses. Si la nueva carga no cabe en el frame, no se libera espacio para una solicitud que no se puede atender.&lt;br /&gt;
&lt;br /&gt;
==== Añadir y quitar entradas de la tabla hash ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_FindFreeSpace&amp;lt;/code&amp;gt; busca una entrada cuyo ID sea &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt;, siguiendo la misma secuencia de pasos de 15.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; guarda el ID y su tiempo de uso, aumenta &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; y aumenta el contador de su hash.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Remove&amp;lt;/code&amp;gt; escribe &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; en el ID retirado y reduce ambos contadores.&lt;br /&gt;
&lt;br /&gt;
Retirar una entrada no borra por sí solo los píxeles de VRAM. Indica que esa pose dejó de estar disponible en la caché; las nuevas transferencias sobrescribirán el espacio elegido.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se representa el mapa de VRAM ===&lt;br /&gt;
&lt;br /&gt;
El mapa representa &#039;&#039;&#039;128 posiciones de tiles de 16×16 en la VRAM de sprites&#039;&#039;&#039;, numeradas de izquierda a derecha y de arriba abajo. Cada bloque es una de esas posiciones, no un tramo de 128 bytes contiguos.&lt;br /&gt;
&lt;br /&gt;
Un tile de 16×16 está formado por cuatro tiles de 8×8 distribuidos en dos filas. El mapa administra las posiciones que ocupa la pose; la distribución de sus datos para cargarlos se resuelve después en &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Posición donde comienza la sección. El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica que está restringida: ese espacio no se utiliza para poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt;, también llamada &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 || 1 || Si el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; está activo, los otros bits guardan la cantidad de posiciones de la sección menos uno. Si está desactivado, guardan el índice hash de la pose que ocupa la sección. Para saber si el espacio está restringido, se consulta &amp;lt;code&amp;gt;Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas dos tablas ocupan &#039;&#039;&#039;256 bytes&#039;&#039;&#039;. Junto con las tablas de poses, el administrador utiliza &#039;&#039;&#039;1025 bytes&#039;&#039;&#039; de RAM, sin contar las listas de transferencias ni las scratch de trabajo.&lt;br /&gt;
&lt;br /&gt;
=== Secciones del mapa ===&lt;br /&gt;
&lt;br /&gt;
Una sección agrupa posiciones consecutivas del mapa que están restringidas, libres o utilizadas por una pose. Su información se guarda en &#039;&#039;&#039;la primera y la última posición&#039;&#039;&#039;. Esto permite saltar de una sección a la anterior sin revisar todas sus posiciones intermedias.&lt;br /&gt;
&lt;br /&gt;
Los siguientes ejemplos muestran tres estados posibles para una sección de 6 posiciones, de &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;. Son casos alternativos, no tres secciones que ocupen el mismo espacio a la vez.&lt;br /&gt;
&lt;br /&gt;
==== Ejemplo 1: sección restringida ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Entradas de las tablas !! Valor !! Significado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$A0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica restringida y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; indica dónde comienza.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$85&amp;lt;/code&amp;gt; || La sección tiene 6 posiciones: &amp;lt;code&amp;gt;($85 AND $7F) + 1 = 6&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Aunque el bit alto de &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt; esté activo, &#039;&#039;&#039;no es espacio libre para poses dinámicas&#039;&#039;&#039;: el bit de restricción en &amp;lt;code&amp;gt;Offset&amp;lt;/code&amp;gt; hace que se descarte. No se evalúa como una pose que pueda reemplazarse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; utiliza este tipo de sección para excluir las partes de SP1-SP4 que no deben utilizar los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
==== Ejemplo 2: sección libre ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Entradas de las tablas !! Valor !! Significado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || Comienza en &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; y no está restringida.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$85&amp;lt;/code&amp;gt; || El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica el tamaño de una sección libre: &amp;lt;code&amp;gt;$05 + 1 = 6&amp;lt;/code&amp;gt; posiciones.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Esta sección sí está disponible. Puede alojar una pose que necesite hasta 6 posiciones; si se coloca una de 4, las otras 2 quedan como otra sección libre.&lt;br /&gt;
&lt;br /&gt;
==== Ejemplo 3: sección utilizada por una pose ====&lt;br /&gt;
&lt;br /&gt;
Supongamos que una pose de 6 bloques está registrada en la entrada hash &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; y ocupa las posiciones &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Entradas de las tablas !! Valor !! Significado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || La sección comienza en &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; y no está restringida.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; está desactivado: &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; es el índice hash de la pose, no su cantidad de bloques.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para conocer la cantidad de posiciones y el tiempo sin uso:&lt;br /&gt;
&lt;br /&gt;
# Se lee el ID de la pose en &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID+$0E&amp;lt;/code&amp;gt;. Se utiliza &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; porque cada ID ocupa 2 bytes y &amp;lt;code&amp;gt;$07 × 2 = $0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Con ese ID se consulta &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt;, que en este ejemplo contiene 6.&lt;br /&gt;
# Se consulta &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse+$0E&amp;lt;/code&amp;gt; para calcular cuánto lleva sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
La entrada &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset+$07&amp;lt;/code&amp;gt; guarda &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;, relacionando esa pose registrada con su posición en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Recorrido y búsqueda de espacio ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; comienza por la posición de tile de 16×16 &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt;. Para recorrer el mapa:&lt;br /&gt;
&lt;br /&gt;
# Lee &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; de la posición actual.&lt;br /&gt;
# Obtiene el comienzo de la sección con &amp;lt;code&amp;gt;Offset AND $7F&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Evalúa esa sección y los espacios que pueda formar con otras secciones contiguas.&lt;br /&gt;
# Pasa a la posición &amp;lt;code&amp;gt;comienzo de la sección - 1&amp;lt;/code&amp;gt;, que es la última posición de la sección anterior.&lt;br /&gt;
# Repite hasta llegar al comienzo del mapa.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si las últimas secciones comienzan en &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Posición visitada !! Comienzo leído de Offset !! Próxima posición&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4F&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Así recorre &#039;&#039;&#039;secciones completas&#039;&#039;&#039;, no cada tile intermedio.&lt;br /&gt;
&lt;br /&gt;
==== Qué se evalúa durante el recorrido ====&lt;br /&gt;
&lt;br /&gt;
El espacio candidato puede ser &#039;&#039;&#039;una sección o varias secciones contiguas&#039;&#039;&#039;. En cada paso se comprueba:&lt;br /&gt;
&lt;br /&gt;
* Si hay una sección restringida, no se utiliza ni se combina a través de ella.&lt;br /&gt;
* Si hay una pose protegida por su uso reciente, tampoco puede formar parte del espacio.&lt;br /&gt;
* Si el candidato todavía es pequeño, se puede continuar con una sección contigua para completar la cantidad de bloques necesaria.&lt;br /&gt;
* Si ya cabe la pose, se compara el candidato con el mejor encontrado: primero por su score de tiempo sin uso y después por el espacio suficiente más pequeño.&lt;br /&gt;
&lt;br /&gt;
No se elige una sección solo por contener la pose con más tiempo sin uso. El &#039;&#039;&#039;espacio completo&#039;&#039;&#039; debe permitir cargar la pose nueva. La puntuación de varias secciones combinadas depende de la pose utilizada más recientemente dentro de ese espacio.&lt;br /&gt;
&lt;br /&gt;
Durante la búsqueda se conservan estos datos temporales:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos de trabajo !! Bytes totales !! Bytes por valor !! Para qué se usan&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapCurrentSpace&amp;lt;/code&amp;gt; || 3 || 1 por campo || Comienzo, score y cantidad de bloques del espacio candidato actual.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapBestSpace&amp;lt;/code&amp;gt; || 3 || 1 por campo || Los mismos campos para el mejor espacio encontrado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapTMP_Size&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de bloques que necesita la pose nueva.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos nombres utilizan scratch de trabajo, no RAM persistente adicional.&lt;br /&gt;
&lt;br /&gt;
=== Política de reemplazo: tiempo sin uso y espacio suficiente ===&lt;br /&gt;
&lt;br /&gt;
El sistema no elige simplemente la pose que se cargó primero. Utiliza el tiempo transcurrido desde su &#039;&#039;&#039;último uso&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tiempo sin uso = DX_Timer - TimeLastUse de la pose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMapSlot_GetSizeAndScore&amp;lt;/code&amp;gt; obtiene el tamaño y una puntuación para cada región:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Puntuación y tratamiento&lt;br /&gt;
|-&lt;br /&gt;
| Región libre || &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Se favorece frente a regiones ocupadas.&lt;br /&gt;
|-&lt;br /&gt;
| Región ocupada || Tiempo sin uso, limitado a &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Tiempo sin uso de 0 o 1 || No se puede reemplazar: la pose sigue protegida.&lt;br /&gt;
|-&lt;br /&gt;
| Región restringida || Se descarta: ese espacio no se utiliza para poses dinámicas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La protección exige &#039;&#039;&#039;al menos dos avances de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; sin utilizar la pose&#039;&#039;&#039;. Cada recurso que vuelve a solicitarla actualiza su tiempo de uso y vuelve a protegerla.&lt;br /&gt;
&lt;br /&gt;
==== Por qué no siempre se reemplaza la pose con más tiempo sin uso ====&lt;br /&gt;
&lt;br /&gt;
La pose nueva necesita espacio suficiente y contiguo. Un espacio pequeño no sirve por sí solo, aunque lleve mucho tiempo sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para una pose nueva de 4 bloques:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Espacio candidato !! Tiempo sin uso !! ¿Sirve?&lt;br /&gt;
|-&lt;br /&gt;
| Pose A: 2 bloques, sin espacio contiguo utilizable || 20 || No: solo deja 2 bloques.&lt;br /&gt;
|-&lt;br /&gt;
| Pose B: 4 bloques || 8 || Sí: puede alojar la pose nueva.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
En este caso se puede reemplazar B y conservar A. A lleva más tiempo sin uso, pero su espacio no permite atender la solicitud.&lt;br /&gt;
&lt;br /&gt;
Si dos o más regiones contiguas pueden reemplazarse, el sistema puede considerarlas juntas. Para esa combinación:&lt;br /&gt;
&lt;br /&gt;
* Suma sus cantidades de bloques.&lt;br /&gt;
* Utiliza la &#039;&#039;&#039;menor puntuación&#039;&#039;&#039; de las regiones combinadas, es decir, el menor tiempo sin uso.&lt;br /&gt;
* Si una está restringida o protegida, no puede utilizarla para completar el espacio.&lt;br /&gt;
&lt;br /&gt;
Así una pose usada recientemente no puede quedar sobrescrita por combinarla con otra que lleva mucho tiempo sin uso.&lt;br /&gt;
&lt;br /&gt;
==== Elegir entre candidatos válidos ====&lt;br /&gt;
&lt;br /&gt;
# El candidato debe tener al menos la cantidad de bloques solicitada.&lt;br /&gt;
# Se prefiere la puntuación más alta: espacio libre o mayor tiempo sin uso.&lt;br /&gt;
# Si las puntuaciones son iguales, se prefiere el candidato con menos bloques, siempre que la pose quepa.&lt;br /&gt;
# Si puntuación y tamaño también coinciden, se conserva el candidato que ya se había elegido.&lt;br /&gt;
&lt;br /&gt;
Las regiones se combinan durante la búsqueda cuando el candidato todavía es demasiado pequeño. No se juntan todas las regiones reemplazables sin tener en cuenta el tamaño solicitado.&lt;br /&gt;
&lt;br /&gt;
=== Reemplazar y dividir la región elegida ===&lt;br /&gt;
&lt;br /&gt;
Una vez elegido el espacio:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemovePosesInSpace&amp;lt;/code&amp;gt; recorre sus regiones y retira de la tabla hash las poses que haya que reemplazar.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemoveSpace&amp;lt;/code&amp;gt; representa el espacio elegido como una región libre, actualizando sus extremos.&lt;br /&gt;
# Se busca una entrada hash libre y se guarda el bloque de comienzo en &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; registra la pose.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_AddPoseInSpace&amp;lt;/code&amp;gt; escribe el índice hash de la pose y el comienzo de su región en el primer y último bloque.&lt;br /&gt;
# Si sobran bloques, crea otra región libre con el resto.&lt;br /&gt;
&lt;br /&gt;
Si una región de 6 bloques aloja una pose de 4, quedan una región ocupada de 4 y una libre de 2. No se mueven las demás poses para compactar VRAM.&lt;br /&gt;
&lt;br /&gt;
=== DynamicRoutine: preparar las transferencias de la pose ===&lt;br /&gt;
&lt;br /&gt;
En este punto ya se eligió el espacio y se registró la pose. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; convierte esa asignación en solicitudes de transferencia.&lt;br /&gt;
&lt;br /&gt;
Utiliza estos datos:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Dato !! Cantidad consultada por pose !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Bloque de comienzo || 1 byte || Lugar elegido por el mapa de VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; || 2 bytes de una tabla de 256 bytes || Convierte uno de los 128 bloques en un desplazamiento de VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 bytes || Dirección completa de los datos de la pose en ROM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 bytes: dos valores de 2 || Cantidad de bytes del primer y del segundo tramo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 bytes || Desplazamiento de VRAM para el segundo tramo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Convertir el bloque en una dirección de VRAM ====&lt;br /&gt;
&lt;br /&gt;
Los bloques de 16×16 no se convierten simplemente en un desplazamiento lineal de bytes. Cada uno utiliza tiles de 8×8 distribuidos en las filas de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; contempla esa distribución. Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bloque !! Desplazamiento !! Dirección de VRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas direcciones de VRAM están expresadas en palabras de 2 bytes, no en bytes. La rutina suma la base &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; utilizada para los gráficos de sprites.&lt;br /&gt;
&lt;br /&gt;
==== Procesar los tramos y sus filas ====&lt;br /&gt;
&lt;br /&gt;
# Obtiene el origen desde &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Procesa los bytes del primer tramo mediante &amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si el segundo tramo tiene tamaño 0, termina.&lt;br /&gt;
# Si existe, adelanta el origen la cantidad de bytes del primer tramo.&lt;br /&gt;
# Suma &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; al desplazamiento de VRAM y procesa el segundo tramo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt; divide cada tramo según las filas y el punto de comienzo. Para un destino V expresado en palabras de VRAM, prepara:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Final de la primera fila = (V + $0100) AND $FF00&lt;br /&gt;
Bytes hasta ese final = (final de la primera fila - V) × 2&lt;br /&gt;
Destino de la segunda parte = final de la primera fila + $0100&lt;br /&gt;
Bytes de la segunda parte de un grupo = $0200 - bytes de la primera&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los tamaños son cantidades de bytes, mientras que los destinos de VRAM están expresados en palabras. Por eso se multiplica por 2 al calcular cuántos datos caben hasta el final de una fila.&lt;br /&gt;
&lt;br /&gt;
La rutina utiliza tres recorridos:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt;: añade una solicitud final con los bytes restantes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLinesWithEndLine&amp;lt;/code&amp;gt;: añade dos solicitudes para los datos restantes, cada una con su destino y cantidad de bytes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLines&amp;lt;/code&amp;gt;: añade dos solicitudes que suman &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, avanza el origen y los destinos y repite con los datos que faltan.&lt;br /&gt;
&lt;br /&gt;
Hay un caso directo antes del recorrido general: si el destino comienza en un límite de &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; palabras y el tramo tiene al menos &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, la rutina utiliza &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt; para preparar la copia del tramo completo en una solicitud.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, un tramo de &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes que comienza en &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; se divide así:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Solicitud !! Origen !! Destino VRAM !! Bytes&lt;br /&gt;
|-&lt;br /&gt;
| Primera || Comienzo del tramo || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt;: 448&lt;br /&gt;
|-&lt;br /&gt;
| Segunda || Comienzo del tramo + &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0040&amp;lt;/code&amp;gt;: 64&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las dos solicitudes copian los 512 bytes del tramo, respetando los destinos que calcula la distribución de filas. No son dos copias completas de la pose.&lt;br /&gt;
&lt;br /&gt;
Cada solicitud utiliza estas tablas:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Por cada solicitud añadida aumenta &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
La cantidad total de bytes de la pose ya se comprobó y se añadió a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;. Esta parte divide esa carga en transferencias; no vuelve a contar la pose completa por cada solicitud.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; &#039;&#039;&#039;no ejecuta DMA&#039;&#039;&#039;. Deja las solicitudes preparadas para que &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt; las copie durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== Qué conserva el sprite ===&lt;br /&gt;
&lt;br /&gt;
Las rutinas de sprites guardan el índice hash de la pose utilizable, no una copia independiente de sus gráficos. Ese índice permite consultar su bloque de VRAM y mantener actualizado su tiempo de uso.&lt;br /&gt;
&lt;br /&gt;
Si una pose nueva no puede cargarse:&lt;br /&gt;
&lt;br /&gt;
* Si existe una pose anterior válida, se mantiene y se actualiza su tiempo de uso para protegerla.&lt;br /&gt;
* Si nunca hubo una pose válida, no se debe dibujar como si la solicitud hubiera tenido éxito.&lt;br /&gt;
* En las llamadas con soporte para mantener la anterior, el carry puede indicar que todavía hay una pose utilizable aunque no se haya completado el cambio.&lt;br /&gt;
&lt;br /&gt;
La animación y el movimiento siguen siendo responsabilidad del sprite. La caché se ocupa de reutilizar o preparar los gráficos solicitados.&lt;br /&gt;
&lt;br /&gt;
== Efectos de paleta: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
El sistema conserva los colores originales para poder cambiar de efecto, combinarlo con otro o volver a la paleta sin efecto. No debe utilizar el resultado ya afectado como si fuera la paleta original.&lt;br /&gt;
&lt;br /&gt;
=== Buffers de colores ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o buffer !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 || 2 por color || Colores de base en formato SNES, con 2 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 || 3 por color || Base separada en rojo, verde y azul, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 || 3 por color || Base separada en tono, saturación y luminosidad, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 || 2 por color || Resultado en formato SNES, listo para solicitar su copia a CGRAM. Corresponde al buffer de paletas del juego.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Indicadores de cada paleta ===&lt;br /&gt;
&lt;br /&gt;
Cada bit de estos indicadores corresponde a una paleta. Las variables &amp;lt;code&amp;gt;BG&amp;lt;/code&amp;gt; cubren 0-7 y las &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt; cubren 8-F.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variables !! Bytes totales !! Bytes por valor !! Qué indican&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si ya se preparó la base de colores en formato SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparada la conversión de la base a RGB.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparada la conversión de la base a HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparado el resultado del efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos indicadores evitan repetir conversiones y cálculos que siguen siendo válidos.&lt;br /&gt;
&lt;br /&gt;
=== Preparar una base ===&lt;br /&gt;
&lt;br /&gt;
# Se comprueba si la paleta ya tiene una base registrada.&lt;br /&gt;
# Si no la tiene, se obtienen los colores del buffer del juego. Una carga explícita, como &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, puede proporcionar esa base directamente.&lt;br /&gt;
# Se comprueba si el efecto necesita RGB o HSL.&lt;br /&gt;
# Si falta esa conversión, se prepara y se marca como disponible.&lt;br /&gt;
&lt;br /&gt;
Si solo cambia el efecto, la base puede seguir siendo válida. Si cambian los colores originales, las llamadas de carga actualizan la base e invalidan las conversiones y resultados que deben calcularse otra vez.&lt;br /&gt;
&lt;br /&gt;
=== Datos de un efecto ===&lt;br /&gt;
&lt;br /&gt;
El ID permite consultar las tablas generadas durante la instalación:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt;: cálculo que debe realizarse.&lt;br /&gt;
* &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt;: valores de los canales o dirección de la paleta de destino de una transición.&lt;br /&gt;
* &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt;: cuánto se aplica cada cambio.&lt;br /&gt;
&lt;br /&gt;
Los canales utilizan valores de 0 a 31. Los ratios van de 0 a 127: 0 conserva el origen y 127 aplica por completo el cambio elegido.&lt;br /&gt;
&lt;br /&gt;
Los cálculos se realizan fuera de NMI. NMI realiza la transferencia de los colores resultantes.&lt;br /&gt;
&lt;br /&gt;
=== Efecto global ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Bytes totales !! Bytes por valor !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 || 2 || Selecciona el efecto global. El valor 0 permite restaurar los colores de base.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta || Selecciona las paletas 0-7 que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta || Selecciona las paletas 8-F que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 32 || 2 || Guarda el último ID global procesado por cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 || 1 || Controla la participación del color fijo y el color 0,0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para cada paleta habilitada, el administrador:&lt;br /&gt;
&lt;br /&gt;
# Comprueba si necesita actualizar el resultado del efecto.&lt;br /&gt;
# Prepara la base RGB o HSL si todavía falta.&lt;br /&gt;
# Calcula el efecto si el resultado anterior ya no sirve.&lt;br /&gt;
# Prepara los colores en formato SNES y solicita su transferencia.&lt;br /&gt;
# Confirma el ID procesado cuando la carga correspondiente se acepta.&lt;br /&gt;
&lt;br /&gt;
Si se mantiene el mismo efecto y no cambió la base, no hace falta calcularlo otra vez. Al cambiar el ID global se invalidan los resultados anteriores, no necesariamente las bases RGB y HSL.&lt;br /&gt;
&lt;br /&gt;
El ID global 0 también requiere una actualización: el sistema debe cargar de nuevo los colores de base para quitar el efecto anterior.&lt;br /&gt;
&lt;br /&gt;
=== Efecto local y concatenación ===&lt;br /&gt;
&lt;br /&gt;
Un recurso puede tener un efecto propio y recibir también el global. Por ejemplo, un sprite puede cambiar de tono y después oscurecerse junto con el nivel.&lt;br /&gt;
&lt;br /&gt;
El orden es:&lt;br /&gt;
&lt;br /&gt;
# Preparar el resultado del efecto local.&lt;br /&gt;
# Utilizarlo como base para el efecto global mediante la llamada de concatenación.&lt;br /&gt;
# Calcular el efecto global sobre esa base.&lt;br /&gt;
# Cargar el resultado combinado, sin mostrar antes la versión que solo tiene el efecto local.&lt;br /&gt;
&lt;br /&gt;
* La concatenación RGB se utiliza con efectos RGB.&lt;br /&gt;
* La concatenación HSL se utiliza con efectos HSL.&lt;br /&gt;
* Los recursos que comparten un destino de CGRAM comparten sus colores. Para mostrar dos efectos locales distintos, necesitan destinos que permitan mantener ambos resultados.&lt;br /&gt;
&lt;br /&gt;
=== Si no se acepta la transferencia ===&lt;br /&gt;
&lt;br /&gt;
* Calcular el efecto no significa que ya esté en CGRAM.&lt;br /&gt;
* Si la transferencia no se acepta, el administrador puede volver a intentar la actualización.&lt;br /&gt;
* Cuando corresponde, se mantiene el resultado anterior utilizable hasta poder sustituirlo.&lt;br /&gt;
* No se deben cargar primero los colores originales sin efecto: podrían verse así durante un frame antes del resultado correcto.&lt;br /&gt;
&lt;br /&gt;
== Cómo trabajan juntos ==&lt;br /&gt;
&lt;br /&gt;
El recorrido de un sprite dinámico reúne estas tareas:&lt;br /&gt;
&lt;br /&gt;
# Su lógica elige la pose y la versión de paleta.&lt;br /&gt;
# La asignación busca una paleta utilizable y prepara los colores si hace falta.&lt;br /&gt;
# La caché protege la pose ya cargada o prepara la carga de una nueva.&lt;br /&gt;
# El dibujo escribe los datos de sus piezas en los buffers OAM.&lt;br /&gt;
# El administrador de efectos prepara los cambios globales pendientes.&lt;br /&gt;
# NMI realiza las transferencias de gráficos y colores solicitadas.&lt;br /&gt;
&lt;br /&gt;
Compartir gráficos, compartir una paleta y compartir una rutina de dibujo son tres cosas distintas. Dynamic Xtreme puede aprovechar cada una sin obligar a que los recursos compartan también las demás.&lt;br /&gt;
&lt;br /&gt;
== Lecturas relacionadas ==&lt;br /&gt;
&lt;br /&gt;
* [[es/Dynamic_Xtreme|Artículo principal]]: funcionalidades y compatibilidad.&lt;br /&gt;
* [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_sprite_creation_guide|Creación de sprites dinámicos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_UberASM_guide|Dynamic Xtreme con UberASM]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_ASM_API|API ASM]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21376</id>
		<title>es/Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21376"/>
		<updated>2026-10-25T03:08:29Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo funciona Dynamic Xtreme, desde la preparación de los recursos al instalarlo hasta la carga y el dibujo de una pose durante el juego.&lt;br /&gt;
&lt;br /&gt;
== Qué prepara la instalación ==&lt;br /&gt;
&lt;br /&gt;
Antes de que un sprite pueda usar sus gráficos o una paleta, Dynamic Xtreme tiene que guardarlos en la ROM y preparar la información para encontrarlos. Lo mismo ocurre con cualquier otro recurso dinámico que hayas añadido.&lt;br /&gt;
&lt;br /&gt;
Para hacerlo, la herramienta lee los DynamicInfo, DrawInfo y PaletteEffect. Cada archivo aporta una parte distinta: qué recursos se van a cargar, cómo se dibujan las poses y qué cambios de color se pueden aplicar.&lt;br /&gt;
&lt;br /&gt;
Gracias a esta preparación se generan defines en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permiten utilizar los recursos y ejecutar fácilmente las rutinas necesarias.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: recursos y datos de carga ===&lt;br /&gt;
&lt;br /&gt;
Un DynamicInfo reúne los gráficos de poses, las paletas y los recursos generales que necesita un sprite u otro código. Si incluye gráficos de poses dinámicas, la herramienta los organiza para que puedan cargarse con la distribución de tiles que espera el sistema.&lt;br /&gt;
&lt;br /&gt;
Por cada pose guarda varios datos en tablas separadas. Todas mantienen el mismo orden: la entrada de una pose en una tabla corresponde a esa misma pose en las demás. En la tabla siguiente, &#039;&#039;&#039;N&#039;&#039;&#039; es la cantidad de poses dinámicas instaladas.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || 2 × N || 2 || La cantidad de datos que utiliza cada pose, en bytes. Se utiliza para comprobar si su carga cabe en el presupuesto del frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || N || 1 || Cuántos bloques de 16×16 hay que reservar en VRAM para la pose. No siempre coincide exactamente con los bytes que se copian, porque una pieza incompleta también puede necesitar un bloque de espacio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 × N || 3 || La dirección de los gráficos de cada pose en ROM. Incluye el banco, de modo que el código de carga pueda encontrar su origen completo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 × N || 2; dos valores por pose || Dos tamaños por pose, correspondientes a los dos tramos en que pueden dividirse sus gráficos. La rutina de carga utiliza esos tamaños para repartirlos correctamente en VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 × N || 2 || El desplazamiento en VRAM desde el comienzo del primer tramo hasta el comienzo del segundo. Permite colocar el segundo tramo donde corresponde, aunque el primero termine con una fila incompleta.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas describen todas las poses instaladas, no solo las que están en pantalla. Más adelante, la caché guarda por separado cuáles están cargadas y dónde quedaron.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si se solicita una pose que todavía no está en VRAM, el sistema consulta cuántos bytes necesita cargar, busca espacio para sus bloques y utiliza la dirección y los datos de sus tramos para preparar la carga.&lt;br /&gt;
&lt;br /&gt;
==== Tablas de paletas ====&lt;br /&gt;
&lt;br /&gt;
Las paletas declaradas en los DynamicInfo se reúnen en &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. Si &#039;&#039;&#039;P&#039;&#039;&#039; es la cantidad de entradas de las listas de paletas de los DynamicInfo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; || 2 × P || 2 || ID de cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; || 3 × P || 3 || Dirección de sus colores en ROM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
P cuenta las entradas de las listas, no solo las paletas distintas: una paleta compartida puede aparecer en más de un DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
Las dos listas siguen el orden de las paletas de los DynamicInfo. El define de offset de cada DynamicInfo indica dónde comienza su lista dentro de ellas. Al elegir una versión, el sistema suma ese índice al offset y obtiene tanto el ID como la dirección de los colores elegidos.&lt;br /&gt;
&lt;br /&gt;
El ID permite reconocer y compartir una paleta; la dirección permite cargarla. No son el número de paleta de pantalla: una misma paleta instalada puede terminar, por ejemplo, en la paleta 9 o en la C según la asignación.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y defines ====&lt;br /&gt;
&lt;br /&gt;
Los archivos declarados en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; se guardan en ROM. Su dirección y la cantidad de bytes que ocupan pueden consultarse mediante los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Por ejemplo, para &amp;lt;code&amp;gt;my_resource.bin&amp;lt;/code&amp;gt; se generan:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt;: dirección del recurso en ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt;: cantidad de bytes que ocupa.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt;: ID del recurso.&lt;br /&gt;
&lt;br /&gt;
El nombre se normaliza en PascalCase: se eliminan espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: datos y rutinas de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El DrawInfo describe cómo está formada una pose: qué tiles tiene, dónde se coloca cada uno, qué tamaño utiliza y cómo cambia al voltearse.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, Dynamic Xtreme genera rutinas de dibujo optimizadas según los parámetros que utilizan los tiles. Tiene en cuenta, por ejemplo, si necesitan desplazamientos X e Y, si comparten el mismo tamaño, si utilizan propiedades comunes y si requieren volteos.&lt;br /&gt;
&lt;br /&gt;
De esta forma, la rutina realiza el trabajo que necesita ese dibujo sin añadir el manejo de opciones que no utiliza. Varias poses pueden compartirla si necesitan el mismo tratamiento; eso no significa que compartan también sus gráficos o su ID.&lt;br /&gt;
&lt;br /&gt;
La relación entre una pose y su dibujo se guarda en estas tablas. &#039;&#039;&#039;D&#039;&#039;&#039; es la cantidad de poses de dibujo y &#039;&#039;&#039;R&#039;&#039;&#039; la cantidad de rutinas generadas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || 2 × D || 2 || Dónde comienzan los datos de la pose dentro de las tablas de su rutina de dibujo. Así se localizan sus tiles y desplazamientos sin recorrer las poses anteriores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || D || 1 || La cantidad de tiles de la pose menos uno. Una pose de cuatro tiles guarda 3; la rutina utiliza ese valor para recorrer sus piezas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || D || 1 || Qué rutina de dibujo utiliza cada pose. Las poses con características compatibles pueden apuntar al mismo ID de rutina.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || 3 × R || 3 por rutina || Las direcciones de las rutinas de dibujo. El ID de rutina permite encontrar aquí el código que debe ejecutarse.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada rutina tiene, además, las tablas que necesitan sus poses. Aquí &#039;&#039;&#039;T&#039;&#039;&#039; es la cantidad de entradas de cada tabla de la rutina:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos !! Bytes totales !! Bytes por valor !! Qué describen&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || T, si se genera || 1 || Los números de tile que forman la pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || T, si se genera || 1 || Las propiedades de cada pieza, como los volteos y su prioridad respecto a las capas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || T por tabla, si se genera || 1 || La posición de cada tile respecto al punto de origen de la pose.&lt;br /&gt;
|-&lt;br /&gt;
| Tablas de desplazamientos para los volteos || T por tabla, si se genera || 1 || Las posiciones que deben utilizarse al voltear la pose cuando necesita una distribución distinta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || T, si se genera || 1 || El tamaño de cada tile: 8×8 o 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
No todas estas tablas tienen que aparecer en todas las rutinas. Si un dato es igual para todas las piezas o puede obtenerse de un valor común, la herramienta puede generar una rutina que lo utilice directamente.&lt;br /&gt;
&lt;br /&gt;
La optimización se hace durante la instalación. Si todos los tiles tienen el mismo tamaño, por ejemplo, la rutina puede utilizar ese valor común sin leer un tamaño distinto para cada pieza.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: datos de los efectos ===&lt;br /&gt;
&lt;br /&gt;
Un archivo PaletteEffect contiene una lista de cambios de color. La instalación les asigna IDs y guarda sus datos en &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Como en las tablas de poses, los datos de cada efecto mantienen la misma posición en las distintas listas. Los IDs de efectos comienzan en 1; el ID 0 se utiliza para indicar que no hay efecto global. En la tabla, &#039;&#039;&#039;E&#039;&#039;&#039; es la cantidad de efectos instalados; el conjunto ocupa &#039;&#039;&#039;2 + 7 × E bytes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parte de la tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || 2 || 2 || La cantidad de efectos instalados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || E || 1 || El tipo de cada efecto, por ejemplo &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Indica qué cálculo debe realizarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || E por tabla; 3 × E entre las tres || 1 por tabla || Los valores de los canales que utiliza el efecto. En una transición, estos tres bytes guardan la dirección de la paleta de destino, no valores de canales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || E por tabla; 3 × E entre las tres || 1 por tabla || Cuánto se aplica el cambio en cada componente. Van de 0 a 127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Si el efecto es una transición hacia otra paleta, la herramienta también prepara esa paleta. Convierte sus colores al formato RGB o HSL que necesita la transición y los guarda en ROM. Durante el juego se puede utilizar ese destino sin tener que convertirlo de nuevo en cada llamada.&lt;br /&gt;
&lt;br /&gt;
Estas paletas de transición son distintas de las paletas normales que se cargan a CGRAM: contienen tres componentes por color y se utilizan para calcular el efecto.&lt;br /&gt;
&lt;br /&gt;
=== Cómo encuentra el código los recursos instalados ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; publica los IDs, direcciones, tamaños y offsets que necesitan los recursos. Por ejemplo, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifica una pose y &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifica el primer efecto de un archivo.&lt;br /&gt;
&lt;br /&gt;
Los nombres se normalizan en PascalCase: se eliminan separadores como espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra. &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, por ejemplo, pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También se genera &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, que guarda las direcciones de los bloques donde se insertaron los recursos. Cada dirección ocupa 3 bytes y se añade un valor final &amp;lt;code&amp;gt;$FFFFFF&amp;lt;/code&amp;gt; de otros 3 bytes. Para B bloques, ocupa &amp;lt;code&amp;gt;3 × (B + 1)&amp;lt;/code&amp;gt; bytes. La herramienta utiliza esa información para localizar los datos de una instalación anterior al reinstalar.&lt;br /&gt;
&lt;br /&gt;
Una reinstalación puede cambiar IDs y direcciones. Por eso hay que volver a insertar los sprites, bloques y códigos UberASM que utilizan los defines generados.&lt;br /&gt;
&lt;br /&gt;
== El trabajo de cada frame ==&lt;br /&gt;
&lt;br /&gt;
En la lógica principal se ejecutan el jugador, los sprites y los demás códigos del modo de juego. Los que utilizan Dynamic Xtreme solicitan las poses y paletas que necesitan, preparan los efectos locales y llaman a las rutinas de dibujo. Las cargas que se aceptan quedan anotadas para transferir sus datos durante NMI.&lt;br /&gt;
&lt;br /&gt;
Al terminar esa lógica, el código de game mode de Dynamic Xtreme realiza las tareas que correspondan a las opciones habilitadas: prepara las actualizaciones de VRAM de la optimización de Kevin, mantiene el estado de las paletas y calcula los efectos globales pendientes.&lt;br /&gt;
&lt;br /&gt;
Después, durante NMI, se ejecutan las transferencias preparadas: los gráficos se copian a VRAM y los colores a CGRAM. También se reinicia el contador de datos y se actualizan los relojes del sistema para el siguiente ciclo de trabajo.&lt;br /&gt;
&lt;br /&gt;
El orden que seguiremos para explicarlo es, por tanto, &#039;&#039;&#039;lógica principal → tareas al terminar el game mode → transferencias durante NMI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Lógica principal ===&lt;br /&gt;
&lt;br /&gt;
Cada recurso decide qué necesita. Un sprite puede cambiar de pose, una animación puede pedir nuevos gráficos y un código UberASM puede cargar una paleta o seleccionar un efecto.&lt;br /&gt;
&lt;br /&gt;
Si la pose solicitada ya está cargada, Dynamic Xtreme actualiza su tiempo de último uso para protegerla del reemplazo y no vuelve a cargar sus gráficos. Si no está cargada, comprueba el presupuesto de datos del frame y busca espacio disponible en VRAM antes de preparar su carga.&lt;br /&gt;
&lt;br /&gt;
El dibujo también se prepara en esta parte: las rutinas escriben en los buffers OAM la posición, los tiles y las propiedades de las piezas que se mostrarán.&lt;br /&gt;
&lt;br /&gt;
Una solicitud puede rechazarse, por ejemplo si no queda presupuesto para sus datos. El recurso que la pidió debe comprobar el resultado y decidir si conserva lo anterior o vuelve a intentarlo después. Una carga rechazada no queda guardada automáticamente para otro frame.&lt;br /&gt;
&lt;br /&gt;
=== Tareas de game mode ===&lt;br /&gt;
&lt;br /&gt;
En esta parte se realizan las siguientes tareas, según las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antes de ejecutar la lógica del juego:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitado &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;, se ejecuta la rutina del control aquí en lugar de hacerlo en NMI.&lt;br /&gt;
# Se comprueba si Dynamic Xtreme debe funcionar en el game mode actual. Si no debe hacerlo, se reinician sus variables. Esto ocurre cada frame que se permanezca en un modo no permitido.&lt;br /&gt;
&lt;br /&gt;
Después se ejecuta la lógica normal del juego, incluidos los sprites y los códigos que solicitan cargas o cambios de paleta.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cuando termina esa lógica:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitada la optimización de VRAM de Kevin, se ajustan los destinos de las actualizaciones de Lunar Magic antes de que se transfieran.&lt;br /&gt;
# Se ponen en 0 los indicadores de actualización de las paletas y se resta 1 a sus temporizadores de protección si todavía son mayores que 0. Esta parte se omite durante la pausa y en los modos no permitidos.&lt;br /&gt;
# Se aplican los efectos globales a las paletas que necesitan actualizarse y se preparan las transferencias de sus colores. Esta parte también se omite si la comprobación anterior impide continuar.&lt;br /&gt;
&lt;br /&gt;
Las copias a VRAM y CGRAM se realizan después, durante NMI. Aquí se deja preparado lo que se va a copiar.&lt;br /&gt;
&lt;br /&gt;
=== Transferencias durante NMI ===&lt;br /&gt;
&lt;br /&gt;
NMI es una interrupción que SNES puede generar al comenzar VBlank, después de dibujar la parte visible de la pantalla. El juego aprovecha ese intervalo para actualizar gráficos, colores y otros datos de video.&lt;br /&gt;
&lt;br /&gt;
En los modos permitidos, la rutina de Dynamic Xtreme reinicia &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; y actualiza sus relojes. Después ejecuta las transferencias de gráficos pendientes y luego las de paletas. Si corresponde, también actualiza el color 0,0 preparado por el sistema de efectos.&lt;br /&gt;
&lt;br /&gt;
Para realizar las copias se utiliza DMA. NMI lee cada carga de las listas, configura desde dónde se copiarán los datos, cuántos bytes se copiarán y dónde se colocarán, y ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
El tiempo de VBlank es limitado y SMW también lo necesita para sus actualizaciones de pantalla. Para limitar la cantidad de datos enviados en un frame y evitar flickering, Dynamic Xtreme utiliza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, que cuenta los bytes de las cargas solicitadas, y &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, que establece el límite permitido. Antes de aceptar una carga normal, se comprueba que sus bytes no hagan superar ese límite.&lt;br /&gt;
&lt;br /&gt;
==== Las listas de transferencias ====&lt;br /&gt;
&lt;br /&gt;
Cada transferencia guarda el origen de los datos, su banco, la cantidad de bytes y el destino en VRAM o CGRAM.&lt;br /&gt;
&lt;br /&gt;
Al realizar las copias, NMI recorre las listas desde la última entrada hacia la primera y después las vacía. Esto no borra los gráficos o colores cargados: permanecen en su destino hasta que otro código los cambie.&lt;br /&gt;
&lt;br /&gt;
La lista de VRAM utiliza 0 cuando no tiene entradas. La de CGRAM utiliza &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, porque guarda el índice de la última entrada en lugar de guardar directamente su cantidad.&lt;br /&gt;
&lt;br /&gt;
Si dos códigos escriben sobre el mismo destino, deben coordinar sus cargas. El orden de las solicitudes no debe utilizarse como sustituto de decidir qué recurso puede ocupar cada espacio.&lt;br /&gt;
&lt;br /&gt;
Normalmente, el recurso se lee desde ROM. Si el recurso se encuentra en un buffer en RAM, el usuario debe conservar su contenido hasta que NMI realice la transferencia. Por ejemplo, si prepara una paleta en RAM, no debe modificar ni reutilizar ese buffer antes de que se copie. La lista guarda su dirección, no una copia de sus datos; Dynamic Xtreme no protege el buffer contra cambios realizados por otros códigos.&lt;br /&gt;
&lt;br /&gt;
==== Presupuesto de datos ====&lt;br /&gt;
&lt;br /&gt;
Las macros de transferencia, como &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt;, comprueban cuántos bytes se han solicitado mediante &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;. Si al añadir la nueva carga se supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, la rechazan. Si la aceptan, suman sus bytes al contador.&lt;br /&gt;
&lt;br /&gt;
El límite predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Su objetivo es evitar flickering por enviar demasiados datos en un mismo frame. Es un límite de cantidad de datos, no una medida exacta del tiempo que tarda cada transferencia.&lt;br /&gt;
&lt;br /&gt;
Estas macros tienen variantes como &amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ForcedTransferToCGRAM()&amp;lt;/code&amp;gt;, que aceptan la carga sin comprobar si supera el límite. Sus bytes también se suman a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, por lo que reducen lo que queda disponible para las siguientes cargas normales. Se utilizan para cargas prioritarias, como las del jugador; usarlas no evita el flickering si se solicita una cantidad excesiva de datos.&lt;br /&gt;
&lt;br /&gt;
==== Los dos relojes ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_Timer: protección de las solicitudes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza cuando se ejecuta la parte de NMI de Dynamic Xtreme. Además de medir cuánto lleva una pose sin utilizarse, sirve para evitar que un recurso repita sus solicitudes antes de que se procesen las anteriores.&lt;br /&gt;
&lt;br /&gt;
No siempre hay un ciclo de lógica por cada ejecución completa de NMI. Durante slowdown, SMW puede ejecutar una versión reducida de NMI, y puede haber dos ciclos de lógica sin que entre ellos se hayan procesado las listas de transferencias de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Sin una protección, un recurso podría añadir otra vez sus cargas a esas listas. Las solicitudes repetidas ocuparían más espacio y podrían provocar flickering.&lt;br /&gt;
&lt;br /&gt;
Para evitarlo, las rutinas con esta protección comparan &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; con un valor guardado por el recurso, normalmente llamado &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt;. Si coinciden, el recurso ya hizo su intento con ese valor del reloj y no debe añadir de nuevo las cargas. Si son distintos, guarda el valor actual y puede realizar la nueva solicitud.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; continúa avanzando durante la pausa cuando se ejecuta esa parte de NMI.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_SyncTimer: animaciones sincronizadas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
La función principal de &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; es dar a los sprites un reloj común para sus animaciones. Por ejemplo, varios sprites que utilizan las mismas poses pueden calcular con este reloj qué pose les corresponde cada cuatro frames.&lt;br /&gt;
&lt;br /&gt;
Así todos cambian al mismo tiempo y solicitan la misma pose. La primera solicitud puede necesitar cargarla; las demás la reutilizan sin programar otra carga de sus gráficos. Esto ahorra transferencias DMA y datos enviados por frame.&lt;br /&gt;
&lt;br /&gt;
Si cada sprite llevara un reloj independiente, podrían terminar usando poses distintas de la misma animación al mismo tiempo y necesitar más cargas y espacio de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; se detiene durante la pausa y cuando se congela la acción, para que las animaciones sincronizadas también se detengan.&lt;br /&gt;
&lt;br /&gt;
== Carga de gráficos: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; guarda en RAM una lista de solicitudes de carga. Durante NMI se recorren esas solicitudes y se copian sus datos a VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Variables de la lista ===&lt;br /&gt;
&lt;br /&gt;
En esta tabla, &#039;&#039;&#039;V&#039;&#039;&#039; es el valor de &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt;: 64 por defecto. Las cuatro tablas de solicitudes reservan V bytes cada una; con entradas de 2 bytes, ese valor deja espacio para 32 solicitudes. Junto con el contador, reservan &amp;lt;code&amp;gt;1 + 4 × V&amp;lt;/code&amp;gt; bytes: 257 por defecto.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de solicitudes pendientes. El valor 0 indica que la lista está vacía.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Dirección de origen de cada solicitud, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 reservados; banco de 1 byte || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Cantidad de bytes que se copiarán.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Dirección de destino en VRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las tablas mantienen el mismo orden: la primera entrada de cada tabla pertenece a la primera solicitud, la segunda a la segunda, etc. Cada entrada de estas tablas ocupa 2 bytes, por lo que se avanza con desplazamientos de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt;, etc.&lt;br /&gt;
&lt;br /&gt;
Estos nombres representan direcciones de RAM calculadas en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus direcciones pueden cambiar según la configuración y las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
=== Añadir una solicitud ===&lt;br /&gt;
&lt;br /&gt;
La macro &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; realiza los siguientes pasos:&lt;br /&gt;
&lt;br /&gt;
# Calcula cuántos bytes habría en total al añadir la nueva carga a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Compara el resultado con &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;. Si lo supera, devuelve el carry desactivado y no añade la solicitud.&lt;br /&gt;
# Utiliza &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para encontrar la siguiente entrada y aumenta ese contador en 1.&lt;br /&gt;
# Guarda el origen, banco, cantidad de bytes y destino en las tablas.&lt;br /&gt;
# Actualiza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; con los bytes de la carga y devuelve el carry activado.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; guarda los mismos datos, pero no comprueba el límite de bytes. Las variantes &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; facilitan obtener el origen desde una dirección completa o desde los defines de un recurso.&lt;br /&gt;
&lt;br /&gt;
Añadir una solicitud no copia los gráficos inmediatamente: deja la información preparada para NMI.&lt;br /&gt;
&lt;br /&gt;
=== Ejecutar las solicitudes durante NMI ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Lee &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;. Si es 0, termina porque no hay solicitudes.&lt;br /&gt;
# Calcula el desplazamiento de la última entrada: &amp;lt;code&amp;gt;(Length - 1) × 2&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Lee su origen, banco y cantidad de bytes, y los coloca en los registros de DMA.&lt;br /&gt;
# Escribe el destino de VRAM en &amp;lt;code&amp;gt;$2116-$2117&amp;lt;/code&amp;gt; e inicia la transferencia mediante &amp;lt;code&amp;gt;$420B&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Retrocede 2 bytes para procesar la solicitud anterior. Repite hasta completar la primera.&lt;br /&gt;
# Escribe 0 en &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para indicar que la lista está vacía.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;La lista se ejecuta del final al inicio.&#039;&#039;&#039; No hace falta borrar todos sus datos al terminar: al quedar su largo en 0, la próxima solicitud volverá a utilizar la primera entrada.&lt;br /&gt;
&lt;br /&gt;
=== Animaciones con un destino fijo ===&lt;br /&gt;
&lt;br /&gt;
El código de una animación debe:&lt;br /&gt;
&lt;br /&gt;
# Elegir la imagen que corresponde al paso actual.&lt;br /&gt;
# Calcular su dirección de origen.&lt;br /&gt;
# Solicitar la copia al destino de VRAM de la animación.&lt;br /&gt;
# Comprobar el carry. Si se rechaza la carga, conservar la imagen anterior y volver a intentarlo.&lt;br /&gt;
&lt;br /&gt;
El destino puede ser siempre el mismo. Lo que cambia es la imagen que se copia allí; la lista de transferencias no decide cuándo debe avanzar la animación.&lt;br /&gt;
&lt;br /&gt;
Puedes ver un código completo en [[es/Dynamic_Xtreme_UberASM_guide#Crear_animaciones_de_gráficos|Crear animaciones de gráficos de la guía de UberASM]].&lt;br /&gt;
&lt;br /&gt;
=== Carga de una pose dinámica ===&lt;br /&gt;
&lt;br /&gt;
La carga de una pose utiliza la caché para no repetir transferencias de gráficos que ya están disponibles:&lt;br /&gt;
&lt;br /&gt;
# Busca el ID en la tabla hash.&lt;br /&gt;
# Si ya está registrado, actualiza su tiempo de uso y no añade otra carga.&lt;br /&gt;
# Si no está, comprueba la cantidad de bytes y busca un espacio adecuado en el mapa de VRAM.&lt;br /&gt;
# Elige qué poses pueden reemplazarse, teniendo en cuenta su tiempo sin uso y el espacio que necesita la nueva.&lt;br /&gt;
# Actualiza las tablas de la caché y el mapa.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; divide los datos de la pose en las transferencias necesarias.&lt;br /&gt;
# NMI ejecuta esas transferencias.&lt;br /&gt;
&lt;br /&gt;
Cada paso se desarrolla en [[#Sprites_dinámicos:_DynamicPoses|Sprites dinámicos: DynamicPoses]], incluyendo la búsqueda por hash, el mapa, la política de reemplazo y la división de la carga en filas.&lt;br /&gt;
&lt;br /&gt;
== Carga y asignación de paletas: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
El sistema distingue dos valores:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID de paleta:&#039;&#039;&#039; identifica los colores guardados en ROM.&lt;br /&gt;
* &#039;&#039;&#039;Destino de pantalla:&#039;&#039;&#039; indica qué paleta de CGRAM utilizará esos colores.&lt;br /&gt;
&lt;br /&gt;
La asignación automática permite compartir colores entre sprites sin exigir un destino fijo para cada uno.&lt;br /&gt;
&lt;br /&gt;
=== Lista de cargas a CGRAM ===&lt;br /&gt;
&lt;br /&gt;
En esta tabla, &#039;&#039;&#039;C&#039;&#039;&#039; es &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt;: 64 por defecto. El conjunto reserva &amp;lt;code&amp;gt;1 + 7 × C&amp;lt;/code&amp;gt; bytes, es decir, 449 con ese valor. Aunque &amp;lt;code&amp;gt;SourceBNK&amp;lt;/code&amp;gt; reserva 2 × C bytes, el código utiliza un byte de banco por solicitud.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Índice de la última solicitud pendiente. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; indica una lista vacía; 0 indica que hay una solicitud.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || 2 × C; 128 por defecto || 2 || Dirección de origen, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || 2 × C; 128 reservados por defecto || 1 utilizado por solicitud || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || 2 × C; 128 por defecto || 2 || Cantidad de bytes que se copiarán. Cada color ocupa 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || C; 64 por defecto || 1 || Primer color de destino en CGRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Durante NMI, &amp;lt;code&amp;gt;CGRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Comienza por la última solicitud pendiente.&lt;br /&gt;
# Configura DMA con el origen y la cantidad de bytes de esa solicitud.&lt;br /&gt;
# Selecciona el primer color mediante &amp;lt;code&amp;gt;$2121&amp;lt;/code&amp;gt; y realiza la copia.&lt;br /&gt;
# Continúa con las solicitudes anteriores.&lt;br /&gt;
# Al terminar, escribe &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; también actualizan las copias de colores y el estado de efectos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Sin efecto global:&#039;&#039;&#039; solicitan la carga y actualizan los buffers de SMW. Así el juego no vuelve a utilizar colores anteriores durante la animación de victoria del goal.&lt;br /&gt;
* &#039;&#039;&#039;Con efecto global:&#039;&#039;&#039; guardan los colores originales y preparan el estado necesario para aplicarles el efecto antes de enviarlos a CGRAM.&lt;br /&gt;
&lt;br /&gt;
=== Asignación automática ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 32 || 2 || Guarda el ID asignado a cada destino. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre y &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; una reservada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 16 || 1 || Protege cada destino del reemplazo automático mientras está en uso.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta de sprites || Indica qué paletas de sprites están asignadas con efecto global habilitado. Esta condición también se compara al compartir una asignación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue este orden:&lt;br /&gt;
&lt;br /&gt;
# Reutilizar una asignación con el mismo ID y una condición de efecto compatible.&lt;br /&gt;
# Si no existe, utilizar una entrada libre.&lt;br /&gt;
# Si no hay entradas libres, reemplazar una que no esté reservada y cuyo temporizador sea 0.&lt;br /&gt;
# Si no encuentra ninguna, indicar que la asignación falló.&lt;br /&gt;
&lt;br /&gt;
Mientras el recurso utiliza la paleta, mantiene su temporizador en 2. Llegar a 0 no borra los colores: la asignación puede reutilizarse si otro recurso todavía no la reemplazó.&lt;br /&gt;
&lt;br /&gt;
=== Asignación manual y versión ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Manual con carga:&#039;&#039;&#039; el código elige el destino y solicita sus colores.&lt;br /&gt;
* &#039;&#039;&#039;Manual sin carga:&#039;&#039;&#039; el código elige el destino y utiliza los colores que ya estaban preparados.&lt;br /&gt;
* &#039;&#039;&#039;Versión:&#039;&#039;&#039; selecciona una entrada de la lista de paletas del DynamicInfo. La última versión procesada permite comprobar si esa selección cambió.&lt;br /&gt;
&lt;br /&gt;
Dos recursos que elijan el mismo destino con colores distintos deben coordinarse. Mantener la protección de una paleta no significa volver a cargar sus colores.&lt;br /&gt;
&lt;br /&gt;
== Dibujo de poses: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
El dibujo prepara las piezas de una pose en OAM: qué tiles se muestran, dónde se colocan y qué propiedades utilizan. Los datos gráficos deben estar en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Pasos del dibujo ===&lt;br /&gt;
&lt;br /&gt;
# Busca la rutina y los datos de la pose mediante &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Obtiene la cantidad de piezas desde &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Calcula la posición de cada tile usando la posición del sprite, sus desplazamientos y los volteos que correspondan.&lt;br /&gt;
# Comprueba si la pieza puede verse y si queda espacio de OAM.&lt;br /&gt;
# Escribe su posición, número de tile, propiedades y tamaño en los buffers OAM.&lt;br /&gt;
&lt;br /&gt;
El número de tile depende del dibujo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Cómo se obtiene el tile&lt;br /&gt;
|-&lt;br /&gt;
| Pose dinámica || Se ajusta al lugar de VRAM donde quedaron cargados sus gráficos.&lt;br /&gt;
|-&lt;br /&gt;
| Pose estática || Se utiliza su número de tile fijo.&lt;br /&gt;
|-&lt;br /&gt;
| Pose que utiliza un tile común || El código debe preparar &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; antes de llamar al dibujo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Prioridad y espacio disponible ===&lt;br /&gt;
&lt;br /&gt;
* En &#039;&#039;&#039;LoROM&#039;&#039;&#039;, el sistema lleva su propio control de entradas OAM disponibles.&lt;br /&gt;
* En &#039;&#039;&#039;SA-1&#039;&#039;&#039;, utiliza la integración con MaxTile.&lt;br /&gt;
* La &#039;&#039;&#039;prioridad de dibujo&#039;&#039;&#039; organiza las piezas de sprites. No es la misma propiedad que determina si un tile queda delante o detrás de las capas.&lt;br /&gt;
* Los &#039;&#039;&#039;límites por línea de pantalla&#039;&#039;&#039; de SNES siguen existiendo. Tener una pose cargada no garantiza que puedan verse todas sus piezas.&lt;br /&gt;
&lt;br /&gt;
== Jugador y Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
El jugador original tiene rutinas propias para elegir y cargar las piezas de sus poses. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; permite integrar ese trabajo con las cargas de Dynamic Xtreme y cambiar el origen de sus gráficos y paletas.&lt;br /&gt;
&lt;br /&gt;
Con el formato original, el juego sigue eligiendo las piezas de la pose. La rutina obtiene sus direcciones desde el origen configurado y compara esas direcciones con las anteriores para cargar las que hayan cambiado.&lt;br /&gt;
&lt;br /&gt;
Estas cargas utilizan transferencias forzadas y sus bytes también cuentan para las solicitudes normales posteriores. Así conservan su prioridad sin quedar fuera de la contabilidad del sistema.&lt;br /&gt;
&lt;br /&gt;
La paleta del jugador tiene un tratamiento especial: combina colores y selecciones del propio juego con el origen personalizado. No funciona simplemente como sustituir una paleta completa de un sprite cualquiera.&lt;br /&gt;
&lt;br /&gt;
El soporte para jugadores personalizados permite que otros sistemas administren de otra forma sus poses y dibujo. No convierte automáticamente cualquier spritesheet al formato del jugador original.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi también carga sus gráficos por piezas. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; permite cambiar su origen manteniendo la organización que esperan sus rutinas.&lt;br /&gt;
&lt;br /&gt;
El código calcula qué partes necesita y prepara sus cargas a los destinos correspondientes de VRAM. Como las del jugador, estas cargas tienen un tratamiento prioritario.&lt;br /&gt;
&lt;br /&gt;
Esta opción necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad. No permite evitar un conflicto del sistema del jugador habilitando únicamente las funciones de Yoshi.&lt;br /&gt;
&lt;br /&gt;
== Memoria y optimizaciones ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW mantiene en RAM gráficos originales del jugador, Yoshi y ciertas animaciones. En ROMs sin SA-1, esta opción adapta las cargas para leer esos datos desde ROM.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aprovecha la RAM recuperada para sus variables internas. No es un espacio que quede libre para que cualquier otro código escriba encima.&lt;br /&gt;
&lt;br /&gt;
SA-1 utiliza otras direcciones y desactiva esta opción. Los rangos están en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
Esta opción mueve el procesamiento del control desde NMI a la parte de game mode. El objetivo es dejar más tiempo para las actualizaciones de pantalla, no añadir un frame de retraso ni cambiar los botones que recibe el juego.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
El color fijo se utiliza en las mezclas de color de la consola. Para actualizarlo, el juego prepara sus componentes y los envía al registro correspondiente.&lt;br /&gt;
&lt;br /&gt;
La optimización reemplaza esa preparación por una secuencia más corta. El color sigue enviándose a la consola, pero necesita menos trabajo durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic utiliza listas llamadas stripe images para actualizar partes de los mapas de tiles. Esas listas incluyen tanto los datos como la información sobre sus destinos.&lt;br /&gt;
&lt;br /&gt;
La versión integrada de la optimización de Kevin prepara fuera de NMI parte del ajuste de esos destinos. Así deja menos trabajo de preparación para el momento de la transferencia.&lt;br /&gt;
&lt;br /&gt;
Esta opción sustituye el uso del parche original por separado. Además, no debe desinstalarse después de instalarla; hay que tenerlo en cuenta antes de activarla.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
La barra de estado original actualiza zonas concretas de VRAM. Esta opción prepara sus transferencias de forma más directa, reduciendo la configuración de DMA que necesita hacer durante NMI.&lt;br /&gt;
&lt;br /&gt;
No añade una barra nueva. Modifica la actualización de la original y, por eso, entra en conflicto con recursos que la reemplazan, modifican o eliminan.&lt;br /&gt;
&lt;br /&gt;
== Sprites dinámicos: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
El sistema funciona como una &#039;&#039;&#039;caché de poses en VRAM&#039;&#039;&#039;. No reserva una copia de los gráficos para cada sprite: guarda la pose y permite que la reutilicen todos los recursos que la necesiten.&lt;br /&gt;
&lt;br /&gt;
* Una pose se carga una sola vez mientras permanezca en la caché.&lt;br /&gt;
* Las siguientes solicitudes actualizan su tiempo de último uso, sin añadir otra carga de sus gráficos.&lt;br /&gt;
* La pose no se borra cuando un recurso deja de utilizarla. Permanece allí hasta que se necesite su espacio y se elija reemplazarla.&lt;br /&gt;
* Si fue reemplazada y vuelve a solicitarse, tendrá que cargarse otra vez.&lt;br /&gt;
&lt;br /&gt;
La elección no depende de cuánto tiempo lleva la pose desde que se cargó, sino de &#039;&#039;&#039;cuánto tiempo lleva sin utilizarse&#039;&#039;&#039; y de si su espacio sirve para la pose nueva.&lt;br /&gt;
&lt;br /&gt;
=== Tres valores distintos ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Qué identifica&lt;br /&gt;
|-&lt;br /&gt;
| ID de pose || La pose instalada. Tiene 16 bits y permite consultar sus datos en ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Índice de la tabla hash || La entrada de RAM donde se registró la pose. Va de 0 a 127.&lt;br /&gt;
|-&lt;br /&gt;
| Bloque de VRAM || ID de una de las 128 posiciones para tiles de 16×16 que caben en el espacio de VRAM de sprites. Se numeran de izquierda a derecha y de arriba abajo, desde 0 hasta 127. Para una pose que ocupa varios bloques, se guarda el ID de su primer bloque.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
El índice de la tabla hash y el bloque de VRAM no tienen por qué coincidir. Una entrada de la tabla puede registrar una pose que empieza en cualquier bloque permitido.&lt;br /&gt;
&lt;br /&gt;
=== Tablas de las poses registradas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de poses registradas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 || 1 || Cantidad de poses registradas para cada hash.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 256 || 2 || ID completo de la pose de cada entrada. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Bloque de VRAM donde comienza cada pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 256 || 2 || Valor de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; de su último uso.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas ocupan &#039;&#039;&#039;769 bytes&#039;&#039;&#039; en RAM. Guardan las poses registradas durante el juego; las tablas generadas desde el DynamicInfo describen, en cambio, todas las poses instaladas.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se busca una pose ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;DynamicPoseHashmap_FindPose&amp;lt;/code&amp;gt; utiliza una tabla hash de 128 entradas. El hash permite elegir dónde empezar a buscar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hash = ID de pose AND $007F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dos IDs diferentes pueden tener el mismo hash. Por ejemplo, &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; producen &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;. Por eso el hash no basta para confirmar que la pose está cargada: también se compara el ID completo.&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue estos pasos:&lt;br /&gt;
&lt;br /&gt;
# Guarda el ID solicitado y calcula su hash.&lt;br /&gt;
# Si &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; es 0, no hay poses registradas y la búsqueda termina.&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize[hash]&amp;lt;/code&amp;gt;. Si es 0, ninguna pose registrada tiene ese hash y también termina.&lt;br /&gt;
# Comienza por la entrada cuyo índice coincide con el hash.&lt;br /&gt;
# Lee el ID de esa entrada. Si coincide con el solicitado, encontró la pose.&lt;br /&gt;
# Si no coincide, continúa con la siguiente entrada de la secuencia de búsqueda.&lt;br /&gt;
&lt;br /&gt;
La secuencia avanza &#039;&#039;&#039;15 entradas por intento&#039;&#039;&#039; y vuelve al comienzo al superar 127:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
siguiente índice = (índice actual + 15) AND $7F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Con 128 entradas, ese paso permite visitar todas las posiciones antes de repetir una. Para el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, el comienzo de la secuencia es:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$05 → $14 → $23 → $32 → $41 → ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== El contador de poses de cada hash ====&lt;br /&gt;
&lt;br /&gt;
Cada hash tiene su propio contador en &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt;. Por ejemplo, si hay dos poses registradas cuyo ID produce el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, la entrada &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize+$05&amp;lt;/code&amp;gt; contiene 2.&lt;br /&gt;
&lt;br /&gt;
Ese número indica &#039;&#039;&#039;cuántas poses con ese hash existen&#039;&#039;&#039;, no cuántas posiciones hay que recorrer. La búsqueda utiliza una copia temporal del contador:&lt;br /&gt;
&lt;br /&gt;
# Comienza con la cantidad de poses registrada para el hash solicitado.&lt;br /&gt;
# Recorre las posiciones de la secuencia hasta encontrar el ID solicitado o haber comprobado esa cantidad de poses con el mismo hash.&lt;br /&gt;
# Cada vez que encuentra una pose con ese hash, pero con otro ID, resta 1 al contador temporal.&lt;br /&gt;
# Las posiciones libres y las poses de otros hashes no descuentan nada: continúa buscando.&lt;br /&gt;
# Si el contador temporal llega a 0 sin encontrar el ID, la pose solicitada no está registrada y la búsqueda termina.&lt;br /&gt;
&lt;br /&gt;
El contador de &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; no se modifica durante esta búsqueda. Solo se actualiza al añadir o retirar poses de la caché.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, se busca &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt;, que produce el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, y el contador de ese hash vale 2:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Posición visitada !! ID guardado !! Hash del ID !! Poses del hash $05 que faltan por comprobar&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 1: tiene el mismo hash, pero no es el ID solicitado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0014&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || 1: es otro hash, así que no se descuenta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$23&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 0: ya se comprobaron las dos poses con ese hash. &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt; no está registrada.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Lo habitual es que haya una o dos poses por hash. Esto permite resolver la búsqueda con pocas comprobaciones y un coste normalmente cercano a &amp;lt;code&amp;gt;O(1)&amp;lt;/code&amp;gt;. No significa que siempre se visiten solo una o dos posiciones: puede haber entradas de otros hashes entre ellas. Con muchas colisiones, el recorrido puede ser más largo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Una entrada libre no termina la búsqueda.&#039;&#039;&#039; Puede haber quedado vacía al reemplazar una pose y existir otra del mismo hash más adelante. El contador permite saber cuándo ya se comprobaron todas las poses de ese hash, incluso si hay huecos entre ellas.&lt;br /&gt;
&lt;br /&gt;
==== Cuando encuentra la pose ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Obtiene el índice de la entrada encontrada.&lt;br /&gt;
# Escribe el valor actual de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; para esa entrada.&lt;br /&gt;
# Devuelve el éxito de la solicitud, sin volver a programar la carga de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
Así todos los recursos que solicitan ese ID utilizan la misma pose y la mantienen protegida. No importa si el recurso es un sprite normal, cluster, extended u otro código que utiliza el sistema.&lt;br /&gt;
&lt;br /&gt;
Esto también evita duplicar una carga dentro del mismo ciclo: cuando la primera solicitud se acepta, la pose ya queda registrada aunque la transferencia física se vaya a realizar durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== Cuando la pose no está registrada ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt; continúa con la preparación de una carga nueva:&lt;br /&gt;
&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; y calcula &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend + PoseSize&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, termina con fallo, sin cambiar las poses existentes.&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; para saber cuántos bloques necesita.&lt;br /&gt;
# Llama a &amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; para buscar un espacio adecuado.&lt;br /&gt;
# Si no existe un espacio utilizable, termina con fallo.&lt;br /&gt;
# Retira del mapa y de la tabla hash las poses que ocupen el espacio elegido.&lt;br /&gt;
# Busca una entrada libre de la tabla hash y registra la pose nueva.&lt;br /&gt;
# Actualiza el mapa de VRAM y el contador de datos del frame.&lt;br /&gt;
# Llama a &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; para añadir las transferencias.&lt;br /&gt;
&lt;br /&gt;
El presupuesto se comprueba antes de reemplazar poses. Si la nueva carga no cabe en el frame, no se libera espacio para una solicitud que no se puede atender.&lt;br /&gt;
&lt;br /&gt;
==== Añadir y quitar entradas de la tabla hash ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_FindFreeSpace&amp;lt;/code&amp;gt; busca una entrada cuyo ID sea &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt;, siguiendo la misma secuencia de pasos de 15.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; guarda el ID y su tiempo de uso, aumenta &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; y aumenta el contador de su hash.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Remove&amp;lt;/code&amp;gt; escribe &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; en el ID retirado y reduce ambos contadores.&lt;br /&gt;
&lt;br /&gt;
Retirar una entrada no borra por sí solo los píxeles de VRAM. Indica que esa pose dejó de estar disponible en la caché; las nuevas transferencias sobrescribirán el espacio elegido.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se representa el mapa de VRAM ===&lt;br /&gt;
&lt;br /&gt;
El mapa representa &#039;&#039;&#039;128 posiciones de tiles de 16×16 en la VRAM de sprites&#039;&#039;&#039;, numeradas de izquierda a derecha y de arriba abajo. Cada bloque es una de esas posiciones, no un tramo de 128 bytes contiguos.&lt;br /&gt;
&lt;br /&gt;
Un tile de 16×16 está formado por cuatro tiles de 8×8 distribuidos en dos filas. El mapa administra las posiciones que ocupa la pose; la distribución de sus datos para cargarlos se resuelve después en &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Posición donde comienza la sección. El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica que está restringida: ese espacio no se utiliza para poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt;, también llamada &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 || 1 || Si el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; está activo, los otros bits guardan la cantidad de posiciones de la sección menos uno. Si está desactivado, guardan el índice hash de la pose que ocupa la sección. Para saber si el espacio está restringido, se consulta &amp;lt;code&amp;gt;Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas dos tablas ocupan &#039;&#039;&#039;256 bytes&#039;&#039;&#039;. Junto con las tablas de poses, el administrador utiliza &#039;&#039;&#039;1025 bytes&#039;&#039;&#039; de RAM, sin contar las listas de transferencias ni las scratch de trabajo.&lt;br /&gt;
&lt;br /&gt;
=== Secciones del mapa ===&lt;br /&gt;
&lt;br /&gt;
Una sección agrupa posiciones consecutivas del mapa que están restringidas, libres o utilizadas por una pose. Su información se guarda en &#039;&#039;&#039;la primera y la última posición&#039;&#039;&#039;. Esto permite saltar de una sección a la anterior sin revisar todas sus posiciones intermedias.&lt;br /&gt;
&lt;br /&gt;
Los siguientes ejemplos muestran tres estados posibles para una sección de 6 posiciones, de &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;. Son casos alternativos, no tres secciones que ocupen el mismo espacio a la vez.&lt;br /&gt;
&lt;br /&gt;
==== Ejemplo 1: sección restringida ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Entradas de las tablas !! Valor !! Significado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$A0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica restringida y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; indica dónde comienza.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$85&amp;lt;/code&amp;gt; || La sección tiene 6 posiciones: &amp;lt;code&amp;gt;($85 AND $7F) + 1 = 6&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Aunque el bit alto de &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt; esté activo, &#039;&#039;&#039;no es espacio libre para poses dinámicas&#039;&#039;&#039;: el bit de restricción en &amp;lt;code&amp;gt;Offset&amp;lt;/code&amp;gt; hace que se descarte. No se evalúa como una pose que pueda reemplazarse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; utiliza este tipo de sección para excluir las partes de SP1-SP4 que no deben utilizar los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
==== Ejemplo 2: sección libre ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Entradas de las tablas !! Valor !! Significado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || Comienza en &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; y no está restringida.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$85&amp;lt;/code&amp;gt; || El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica el tamaño de una sección libre: &amp;lt;code&amp;gt;$05 + 1 = 6&amp;lt;/code&amp;gt; posiciones.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Esta sección sí está disponible. Puede alojar una pose que necesite hasta 6 posiciones; si se coloca una de 4, las otras 2 quedan como otra sección libre.&lt;br /&gt;
&lt;br /&gt;
==== Ejemplo 3: sección utilizada por una pose ====&lt;br /&gt;
&lt;br /&gt;
Supongamos que una pose de 6 bloques está registrada en la entrada hash &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; y ocupa las posiciones &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Entradas de las tablas !! Valor !! Significado&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || La sección comienza en &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; y no está restringida.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size+$20&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;+$25&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; está desactivado: &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; es el índice hash de la pose, no su cantidad de bloques.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para conocer la cantidad de posiciones y el tiempo sin uso:&lt;br /&gt;
&lt;br /&gt;
# Se lee el ID de la pose en &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID+$0E&amp;lt;/code&amp;gt;. Se utiliza &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; porque cada ID ocupa 2 bytes y &amp;lt;code&amp;gt;$07 × 2 = $0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Con ese ID se consulta &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt;, que en este ejemplo contiene 6.&lt;br /&gt;
# Se consulta &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse+$0E&amp;lt;/code&amp;gt; para calcular cuánto lleva sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
La entrada &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset+$07&amp;lt;/code&amp;gt; guarda &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;, relacionando esa pose registrada con su posición en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Recorrido y búsqueda de espacio ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; comienza por la posición de tile de 16×16 &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt;. Para recorrer el mapa:&lt;br /&gt;
&lt;br /&gt;
# Lee &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; de la posición actual.&lt;br /&gt;
# Obtiene el comienzo de la sección con &amp;lt;code&amp;gt;Offset AND $7F&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Evalúa esa sección y los espacios que pueda formar con otras secciones contiguas.&lt;br /&gt;
# Pasa a la posición &amp;lt;code&amp;gt;comienzo de la sección - 1&amp;lt;/code&amp;gt;, que es la última posición de la sección anterior.&lt;br /&gt;
# Repite hasta llegar al comienzo del mapa.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si las últimas secciones comienzan en &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Posición visitada !! Comienzo leído de Offset !! Próxima posición&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$6F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$60&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$50&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4F&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Así recorre &#039;&#039;&#039;secciones completas&#039;&#039;&#039;, no cada tile intermedio.&lt;br /&gt;
&lt;br /&gt;
==== Qué se evalúa durante el recorrido ====&lt;br /&gt;
&lt;br /&gt;
El espacio candidato puede ser &#039;&#039;&#039;una sección o varias secciones contiguas&#039;&#039;&#039;. En cada paso se comprueba:&lt;br /&gt;
&lt;br /&gt;
* Si hay una sección restringida, no se utiliza ni se combina a través de ella.&lt;br /&gt;
* Si hay una pose protegida por su uso reciente, tampoco puede formar parte del espacio.&lt;br /&gt;
* Si el candidato todavía es pequeño, se puede continuar con una sección contigua para completar la cantidad de bloques necesaria.&lt;br /&gt;
* Si ya cabe la pose, se compara el candidato con el mejor encontrado: primero por su score de tiempo sin uso y después por el espacio suficiente más pequeño.&lt;br /&gt;
&lt;br /&gt;
No se elige una sección solo por contener la pose con más tiempo sin uso. El &#039;&#039;&#039;espacio completo&#039;&#039;&#039; debe permitir cargar la pose nueva. La puntuación de varias secciones combinadas depende de la pose utilizada más recientemente dentro de ese espacio.&lt;br /&gt;
&lt;br /&gt;
Durante la búsqueda se conservan estos datos temporales:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos de trabajo !! Bytes totales !! Bytes por valor !! Para qué se usan&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapCurrentSpace&amp;lt;/code&amp;gt; || 3 || 1 por campo || Comienzo, score y cantidad de bloques del espacio candidato actual.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapBestSpace&amp;lt;/code&amp;gt; || 3 || 1 por campo || Los mismos campos para el mejor espacio encontrado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapTMP_Size&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de bloques que necesita la pose nueva.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos nombres utilizan scratch de trabajo, no RAM persistente adicional.&lt;br /&gt;
&lt;br /&gt;
=== Política de reemplazo: tiempo sin uso y espacio suficiente ===&lt;br /&gt;
&lt;br /&gt;
El sistema no elige simplemente la pose que se cargó primero. Utiliza el tiempo transcurrido desde su &#039;&#039;&#039;último uso&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tiempo sin uso = DX_Timer - TimeLastUse de la pose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMapSlot_GetSizeAndScore&amp;lt;/code&amp;gt; obtiene el tamaño y una puntuación para cada región:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Puntuación y tratamiento&lt;br /&gt;
|-&lt;br /&gt;
| Región libre || &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Se favorece frente a regiones ocupadas.&lt;br /&gt;
|-&lt;br /&gt;
| Región ocupada || Tiempo sin uso, limitado a &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Tiempo sin uso de 0 o 1 || No se puede reemplazar: la pose sigue protegida.&lt;br /&gt;
|-&lt;br /&gt;
| Región restringida || Se descarta: ese espacio no se utiliza para poses dinámicas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La protección exige &#039;&#039;&#039;al menos dos avances de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; sin utilizar la pose&#039;&#039;&#039;. Cada recurso que vuelve a solicitarla actualiza su tiempo de uso y vuelve a protegerla.&lt;br /&gt;
&lt;br /&gt;
==== Por qué no siempre se reemplaza la pose con más tiempo sin uso ====&lt;br /&gt;
&lt;br /&gt;
La pose nueva necesita espacio suficiente y contiguo. Un espacio pequeño no sirve por sí solo, aunque lleve mucho tiempo sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para una pose nueva de 4 bloques:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Espacio candidato !! Tiempo sin uso !! ¿Sirve?&lt;br /&gt;
|-&lt;br /&gt;
| Pose A: 2 bloques, sin espacio contiguo utilizable || 20 || No: solo deja 2 bloques.&lt;br /&gt;
|-&lt;br /&gt;
| Pose B: 4 bloques || 8 || Sí: puede alojar la pose nueva.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
En este caso se puede reemplazar B y conservar A. A lleva más tiempo sin uso, pero su espacio no permite atender la solicitud.&lt;br /&gt;
&lt;br /&gt;
Si dos o más regiones contiguas pueden reemplazarse, el sistema puede considerarlas juntas. Para esa combinación:&lt;br /&gt;
&lt;br /&gt;
* Suma sus cantidades de bloques.&lt;br /&gt;
* Utiliza la &#039;&#039;&#039;menor puntuación&#039;&#039;&#039; de las regiones combinadas, es decir, el menor tiempo sin uso.&lt;br /&gt;
* Si una está restringida o protegida, no puede utilizarla para completar el espacio.&lt;br /&gt;
&lt;br /&gt;
Así una pose usada recientemente no puede quedar sobrescrita por combinarla con otra que lleva mucho tiempo sin uso.&lt;br /&gt;
&lt;br /&gt;
==== Elegir entre candidatos válidos ====&lt;br /&gt;
&lt;br /&gt;
# El candidato debe tener al menos la cantidad de bloques solicitada.&lt;br /&gt;
# Se prefiere la puntuación más alta: espacio libre o mayor tiempo sin uso.&lt;br /&gt;
# Si las puntuaciones son iguales, se prefiere el candidato con menos bloques, siempre que la pose quepa.&lt;br /&gt;
# Si puntuación y tamaño también coinciden, se conserva el candidato que ya se había elegido.&lt;br /&gt;
&lt;br /&gt;
Las regiones se combinan durante la búsqueda cuando el candidato todavía es demasiado pequeño. No se juntan todas las regiones reemplazables sin tener en cuenta el tamaño solicitado.&lt;br /&gt;
&lt;br /&gt;
=== Reemplazar y dividir la región elegida ===&lt;br /&gt;
&lt;br /&gt;
Una vez elegido el espacio:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemovePosesInSpace&amp;lt;/code&amp;gt; recorre sus regiones y retira de la tabla hash las poses que haya que reemplazar.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemoveSpace&amp;lt;/code&amp;gt; representa el espacio elegido como una región libre, actualizando sus extremos.&lt;br /&gt;
# Se busca una entrada hash libre y se guarda el bloque de comienzo en &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; registra la pose.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_AddPoseInSpace&amp;lt;/code&amp;gt; escribe el índice hash de la pose y el comienzo de su región en el primer y último bloque.&lt;br /&gt;
# Si sobran bloques, crea otra región libre con el resto.&lt;br /&gt;
&lt;br /&gt;
Si una región de 6 bloques aloja una pose de 4, quedan una región ocupada de 4 y una libre de 2. No se mueven las demás poses para compactar VRAM.&lt;br /&gt;
&lt;br /&gt;
=== DynamicRoutine: preparar las transferencias de la pose ===&lt;br /&gt;
&lt;br /&gt;
En este punto ya se eligió el espacio y se registró la pose. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; convierte esa asignación en solicitudes de transferencia.&lt;br /&gt;
&lt;br /&gt;
Utiliza estos datos:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Dato !! Cantidad consultada por pose !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Bloque de comienzo || 1 byte || Lugar elegido por el mapa de VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; || 2 bytes de una tabla de 256 bytes || Convierte uno de los 128 bloques en un desplazamiento de VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 bytes || Dirección completa de los datos de la pose en ROM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 bytes: dos valores de 2 || Cantidad de bytes del primer y del segundo tramo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 bytes || Desplazamiento de VRAM para el segundo tramo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Convertir el bloque en una dirección de VRAM ====&lt;br /&gt;
&lt;br /&gt;
Los bloques de 16×16 no se convierten simplemente en un desplazamiento lineal de bytes. Cada uno utiliza tiles de 8×8 distribuidos en las filas de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; contempla esa distribución. Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bloque !! Desplazamiento !! Dirección de VRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas direcciones de VRAM están expresadas en palabras de 2 bytes, no en bytes. La rutina suma la base &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; utilizada para los gráficos de sprites.&lt;br /&gt;
&lt;br /&gt;
==== Procesar los tramos y sus filas ====&lt;br /&gt;
&lt;br /&gt;
# Obtiene el origen desde &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Procesa los bytes del primer tramo mediante &amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si el segundo tramo tiene tamaño 0, termina.&lt;br /&gt;
# Si existe, adelanta el origen la cantidad de bytes del primer tramo.&lt;br /&gt;
# Suma &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; al desplazamiento de VRAM y procesa el segundo tramo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt; divide cada tramo según las filas y el punto de comienzo. Para un destino V expresado en palabras de VRAM, prepara:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Final de la primera fila = (V + $0100) AND $FF00&lt;br /&gt;
Bytes hasta ese final = (final de la primera fila - V) × 2&lt;br /&gt;
Destino de la segunda parte = final de la primera fila + $0100&lt;br /&gt;
Bytes de la segunda parte de un grupo = $0200 - bytes de la primera&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los tamaños son cantidades de bytes, mientras que los destinos de VRAM están expresados en palabras. Por eso se multiplica por 2 al calcular cuántos datos caben hasta el final de una fila.&lt;br /&gt;
&lt;br /&gt;
La rutina utiliza tres recorridos:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt;: añade una solicitud final con los bytes restantes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLinesWithEndLine&amp;lt;/code&amp;gt;: añade dos solicitudes para los datos restantes, cada una con su destino y cantidad de bytes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLines&amp;lt;/code&amp;gt;: añade dos solicitudes que suman &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, avanza el origen y los destinos y repite con los datos que faltan.&lt;br /&gt;
&lt;br /&gt;
Hay un caso directo antes del recorrido general: si el destino comienza en un límite de &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; palabras y el tramo tiene al menos &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, la rutina utiliza &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt; para preparar la copia del tramo completo en una solicitud.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, un tramo de &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes que comienza en &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; se divide así:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Solicitud !! Origen !! Destino VRAM !! Bytes&lt;br /&gt;
|-&lt;br /&gt;
| Primera || Comienzo del tramo || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt;: 448&lt;br /&gt;
|-&lt;br /&gt;
| Segunda || Comienzo del tramo + &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0040&amp;lt;/code&amp;gt;: 64&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las dos solicitudes copian los 512 bytes del tramo, respetando los destinos que calcula la distribución de filas. No son dos copias completas de la pose.&lt;br /&gt;
&lt;br /&gt;
Cada solicitud utiliza estas tablas:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Por cada solicitud añadida aumenta &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
La cantidad total de bytes de la pose ya se comprobó y se añadió a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;. Esta parte divide esa carga en transferencias; no vuelve a contar la pose completa por cada solicitud.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; &#039;&#039;&#039;no ejecuta DMA&#039;&#039;&#039;. Deja las solicitudes preparadas para que &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt; las copie durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== Qué conserva el sprite ===&lt;br /&gt;
&lt;br /&gt;
Las rutinas de sprites guardan el índice hash de la pose utilizable, no una copia independiente de sus gráficos. Ese índice permite consultar su bloque de VRAM y mantener actualizado su tiempo de uso.&lt;br /&gt;
&lt;br /&gt;
Si una pose nueva no puede cargarse:&lt;br /&gt;
&lt;br /&gt;
* Si existe una pose anterior válida, se mantiene y se actualiza su tiempo de uso para protegerla.&lt;br /&gt;
* Si nunca hubo una pose válida, no se debe dibujar como si la solicitud hubiera tenido éxito.&lt;br /&gt;
* En las llamadas con soporte para mantener la anterior, el carry puede indicar que todavía hay una pose utilizable aunque no se haya completado el cambio.&lt;br /&gt;
&lt;br /&gt;
La animación y el movimiento siguen siendo responsabilidad del sprite. La caché se ocupa de reutilizar o preparar los gráficos solicitados.&lt;br /&gt;
&lt;br /&gt;
== Efectos de paleta: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
El sistema conserva los colores originales para poder cambiar de efecto, combinarlo con otro o volver a la paleta sin efecto. No debe utilizar el resultado ya afectado como si fuera la paleta original.&lt;br /&gt;
&lt;br /&gt;
=== Buffers de colores ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o buffer !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 || 2 por color || Colores de base en formato SNES, con 2 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 || 3 por color || Base separada en rojo, verde y azul, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 || 3 por color || Base separada en tono, saturación y luminosidad, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 || 2 por color || Resultado en formato SNES, listo para solicitar su copia a CGRAM. Corresponde al buffer de paletas del juego.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Indicadores de cada paleta ===&lt;br /&gt;
&lt;br /&gt;
Cada bit de estos indicadores corresponde a una paleta. Las variables &amp;lt;code&amp;gt;BG&amp;lt;/code&amp;gt; cubren 0-7 y las &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt; cubren 8-F.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variables !! Bytes totales !! Bytes por valor !! Qué indican&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si ya se preparó la base de colores en formato SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparada la conversión de la base a RGB.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparada la conversión de la base a HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparado el resultado del efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos indicadores evitan repetir conversiones y cálculos que siguen siendo válidos.&lt;br /&gt;
&lt;br /&gt;
=== Preparar una base ===&lt;br /&gt;
&lt;br /&gt;
# Se comprueba si la paleta ya tiene una base registrada.&lt;br /&gt;
# Si no la tiene, se obtienen los colores del buffer del juego. Una carga explícita, como &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, puede proporcionar esa base directamente.&lt;br /&gt;
# Se comprueba si el efecto necesita RGB o HSL.&lt;br /&gt;
# Si falta esa conversión, se prepara y se marca como disponible.&lt;br /&gt;
&lt;br /&gt;
Si solo cambia el efecto, la base puede seguir siendo válida. Si cambian los colores originales, las llamadas de carga actualizan la base e invalidan las conversiones y resultados que deben calcularse otra vez.&lt;br /&gt;
&lt;br /&gt;
=== Datos de un efecto ===&lt;br /&gt;
&lt;br /&gt;
El ID permite consultar las tablas generadas durante la instalación:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt;: cálculo que debe realizarse.&lt;br /&gt;
* &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt;: valores de los canales o dirección de la paleta de destino de una transición.&lt;br /&gt;
* &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt;: cuánto se aplica cada cambio.&lt;br /&gt;
&lt;br /&gt;
Los canales utilizan valores de 0 a 31. Los ratios van de 0 a 127: 0 conserva el origen y 127 aplica por completo el cambio elegido.&lt;br /&gt;
&lt;br /&gt;
Los cálculos se realizan fuera de NMI. NMI realiza la transferencia de los colores resultantes.&lt;br /&gt;
&lt;br /&gt;
=== Efecto global ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Bytes totales !! Bytes por valor !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 || 2 || Selecciona el efecto global. El valor 0 permite restaurar los colores de base.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta || Selecciona las paletas 0-7 que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta || Selecciona las paletas 8-F que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 32 || 2 || Guarda el último ID global procesado por cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 || 1 || Controla la participación del color fijo y el color 0,0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para cada paleta habilitada, el administrador:&lt;br /&gt;
&lt;br /&gt;
# Comprueba si necesita actualizar el resultado del efecto.&lt;br /&gt;
# Prepara la base RGB o HSL si todavía falta.&lt;br /&gt;
# Calcula el efecto si el resultado anterior ya no sirve.&lt;br /&gt;
# Prepara los colores en formato SNES y solicita su transferencia.&lt;br /&gt;
# Confirma el ID procesado cuando la carga correspondiente se acepta.&lt;br /&gt;
&lt;br /&gt;
Si se mantiene el mismo efecto y no cambió la base, no hace falta calcularlo otra vez. Al cambiar el ID global se invalidan los resultados anteriores, no necesariamente las bases RGB y HSL.&lt;br /&gt;
&lt;br /&gt;
El ID global 0 también requiere una actualización: el sistema debe cargar de nuevo los colores de base para quitar el efecto anterior.&lt;br /&gt;
&lt;br /&gt;
=== Efecto local y concatenación ===&lt;br /&gt;
&lt;br /&gt;
Un recurso puede tener un efecto propio y recibir también el global. Por ejemplo, un sprite puede cambiar de tono y después oscurecerse junto con el nivel.&lt;br /&gt;
&lt;br /&gt;
El orden es:&lt;br /&gt;
&lt;br /&gt;
# Preparar el resultado del efecto local.&lt;br /&gt;
# Utilizarlo como base para el efecto global mediante la llamada de concatenación.&lt;br /&gt;
# Calcular el efecto global sobre esa base.&lt;br /&gt;
# Cargar el resultado combinado, sin mostrar antes la versión que solo tiene el efecto local.&lt;br /&gt;
&lt;br /&gt;
* La concatenación RGB se utiliza con efectos RGB.&lt;br /&gt;
* La concatenación HSL se utiliza con efectos HSL.&lt;br /&gt;
* Los recursos que comparten un destino de CGRAM comparten sus colores. Para mostrar dos efectos locales distintos, necesitan destinos que permitan mantener ambos resultados.&lt;br /&gt;
&lt;br /&gt;
=== Si no se acepta la transferencia ===&lt;br /&gt;
&lt;br /&gt;
* Calcular el efecto no significa que ya esté en CGRAM.&lt;br /&gt;
* Si la transferencia no se acepta, el administrador puede volver a intentar la actualización.&lt;br /&gt;
* Cuando corresponde, se mantiene el resultado anterior utilizable hasta poder sustituirlo.&lt;br /&gt;
* No se deben cargar primero los colores originales sin efecto: podrían verse así durante un frame antes del resultado correcto.&lt;br /&gt;
&lt;br /&gt;
== Cómo trabajan juntos ==&lt;br /&gt;
&lt;br /&gt;
El recorrido de un sprite dinámico reúne estas tareas:&lt;br /&gt;
&lt;br /&gt;
# Su lógica elige la pose y la versión de paleta.&lt;br /&gt;
# La asignación busca una paleta utilizable y prepara los colores si hace falta.&lt;br /&gt;
# La caché protege la pose ya cargada o prepara la carga de una nueva.&lt;br /&gt;
# El dibujo escribe los datos de sus piezas en los buffers OAM.&lt;br /&gt;
# El administrador de efectos prepara los cambios globales pendientes.&lt;br /&gt;
# NMI realiza las transferencias de gráficos y colores solicitadas.&lt;br /&gt;
&lt;br /&gt;
Compartir gráficos, compartir una paleta y compartir una rutina de dibujo son tres cosas distintas. Dynamic Xtreme puede aprovechar cada una sin obligar a que los recursos compartan también las demás.&lt;br /&gt;
&lt;br /&gt;
== Lecturas relacionadas ==&lt;br /&gt;
&lt;br /&gt;
* [[es/Dynamic_Xtreme|Artículo principal]]: funcionalidades y compatibilidad.&lt;br /&gt;
* [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_sprite_creation_guide|Creación de sprites dinámicos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_UberASM_guide|Dynamic Xtreme con UberASM]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_ASM_API|API ASM]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21375</id>
		<title>es/Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21375"/>
		<updated>2026-10-25T02:49:13Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo funciona Dynamic Xtreme, desde la preparación de los recursos al instalarlo hasta la carga y el dibujo de una pose durante el juego.&lt;br /&gt;
&lt;br /&gt;
== Qué prepara la instalación ==&lt;br /&gt;
&lt;br /&gt;
Antes de que un sprite pueda usar sus gráficos o una paleta, Dynamic Xtreme tiene que guardarlos en la ROM y preparar la información para encontrarlos. Lo mismo ocurre con cualquier otro recurso dinámico que hayas añadido.&lt;br /&gt;
&lt;br /&gt;
Para hacerlo, la herramienta lee los DynamicInfo, DrawInfo y PaletteEffect. Cada archivo aporta una parte distinta: qué recursos se van a cargar, cómo se dibujan las poses y qué cambios de color se pueden aplicar.&lt;br /&gt;
&lt;br /&gt;
Gracias a esta preparación se generan defines en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permiten utilizar los recursos y ejecutar fácilmente las rutinas necesarias.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: recursos y datos de carga ===&lt;br /&gt;
&lt;br /&gt;
Un DynamicInfo reúne los gráficos de poses, las paletas y los recursos generales que necesita un sprite u otro código. Si incluye gráficos de poses dinámicas, la herramienta los organiza para que puedan cargarse con la distribución de tiles que espera el sistema.&lt;br /&gt;
&lt;br /&gt;
Por cada pose guarda varios datos en tablas separadas. Todas mantienen el mismo orden: la entrada de una pose en una tabla corresponde a esa misma pose en las demás. En la tabla siguiente, &#039;&#039;&#039;N&#039;&#039;&#039; es la cantidad de poses dinámicas instaladas.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || 2 × N || 2 || La cantidad de datos que utiliza cada pose, en bytes. Se utiliza para comprobar si su carga cabe en el presupuesto del frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || N || 1 || Cuántos bloques de 16×16 hay que reservar en VRAM para la pose. No siempre coincide exactamente con los bytes que se copian, porque una pieza incompleta también puede necesitar un bloque de espacio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 × N || 3 || La dirección de los gráficos de cada pose en ROM. Incluye el banco, de modo que el código de carga pueda encontrar su origen completo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 × N || 2; dos valores por pose || Dos tamaños por pose, correspondientes a los dos tramos en que pueden dividirse sus gráficos. La rutina de carga utiliza esos tamaños para repartirlos correctamente en VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 × N || 2 || El desplazamiento en VRAM desde el comienzo del primer tramo hasta el comienzo del segundo. Permite colocar el segundo tramo donde corresponde, aunque el primero termine con una fila incompleta.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas describen todas las poses instaladas, no solo las que están en pantalla. Más adelante, la caché guarda por separado cuáles están cargadas y dónde quedaron.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si se solicita una pose que todavía no está en VRAM, el sistema consulta cuántos bytes necesita cargar, busca espacio para sus bloques y utiliza la dirección y los datos de sus tramos para preparar la carga.&lt;br /&gt;
&lt;br /&gt;
==== Tablas de paletas ====&lt;br /&gt;
&lt;br /&gt;
Las paletas declaradas en los DynamicInfo se reúnen en &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. Si &#039;&#039;&#039;P&#039;&#039;&#039; es la cantidad de entradas de las listas de paletas de los DynamicInfo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; || 2 × P || 2 || ID de cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; || 3 × P || 3 || Dirección de sus colores en ROM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
P cuenta las entradas de las listas, no solo las paletas distintas: una paleta compartida puede aparecer en más de un DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
Las dos listas siguen el orden de las paletas de los DynamicInfo. El define de offset de cada DynamicInfo indica dónde comienza su lista dentro de ellas. Al elegir una versión, el sistema suma ese índice al offset y obtiene tanto el ID como la dirección de los colores elegidos.&lt;br /&gt;
&lt;br /&gt;
El ID permite reconocer y compartir una paleta; la dirección permite cargarla. No son el número de paleta de pantalla: una misma paleta instalada puede terminar, por ejemplo, en la paleta 9 o en la C según la asignación.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y defines ====&lt;br /&gt;
&lt;br /&gt;
Los archivos declarados en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; se guardan en ROM. Su dirección y la cantidad de bytes que ocupan pueden consultarse mediante los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Por ejemplo, para &amp;lt;code&amp;gt;my_resource.bin&amp;lt;/code&amp;gt; se generan:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt;: dirección del recurso en ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt;: cantidad de bytes que ocupa.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt;: ID del recurso.&lt;br /&gt;
&lt;br /&gt;
El nombre se normaliza en PascalCase: se eliminan espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: datos y rutinas de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El DrawInfo describe cómo está formada una pose: qué tiles tiene, dónde se coloca cada uno, qué tamaño utiliza y cómo cambia al voltearse.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, Dynamic Xtreme genera rutinas de dibujo optimizadas según los parámetros que utilizan los tiles. Tiene en cuenta, por ejemplo, si necesitan desplazamientos X e Y, si comparten el mismo tamaño, si utilizan propiedades comunes y si requieren volteos.&lt;br /&gt;
&lt;br /&gt;
De esta forma, la rutina realiza el trabajo que necesita ese dibujo sin añadir el manejo de opciones que no utiliza. Varias poses pueden compartirla si necesitan el mismo tratamiento; eso no significa que compartan también sus gráficos o su ID.&lt;br /&gt;
&lt;br /&gt;
La relación entre una pose y su dibujo se guarda en estas tablas. &#039;&#039;&#039;D&#039;&#039;&#039; es la cantidad de poses de dibujo y &#039;&#039;&#039;R&#039;&#039;&#039; la cantidad de rutinas generadas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || 2 × D || 2 || Dónde comienzan los datos de la pose dentro de las tablas de su rutina de dibujo. Así se localizan sus tiles y desplazamientos sin recorrer las poses anteriores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || D || 1 || La cantidad de tiles de la pose menos uno. Una pose de cuatro tiles guarda 3; la rutina utiliza ese valor para recorrer sus piezas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || D || 1 || Qué rutina de dibujo utiliza cada pose. Las poses con características compatibles pueden apuntar al mismo ID de rutina.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || 3 × R || 3 por rutina || Las direcciones de las rutinas de dibujo. El ID de rutina permite encontrar aquí el código que debe ejecutarse.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada rutina tiene, además, las tablas que necesitan sus poses. Aquí &#039;&#039;&#039;T&#039;&#039;&#039; es la cantidad de entradas de cada tabla de la rutina:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos !! Bytes totales !! Bytes por valor !! Qué describen&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || T, si se genera || 1 || Los números de tile que forman la pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || T, si se genera || 1 || Las propiedades de cada pieza, como los volteos y su prioridad respecto a las capas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || T por tabla, si se genera || 1 || La posición de cada tile respecto al punto de origen de la pose.&lt;br /&gt;
|-&lt;br /&gt;
| Tablas de desplazamientos para los volteos || T por tabla, si se genera || 1 || Las posiciones que deben utilizarse al voltear la pose cuando necesita una distribución distinta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || T, si se genera || 1 || El tamaño de cada tile: 8×8 o 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
No todas estas tablas tienen que aparecer en todas las rutinas. Si un dato es igual para todas las piezas o puede obtenerse de un valor común, la herramienta puede generar una rutina que lo utilice directamente.&lt;br /&gt;
&lt;br /&gt;
La optimización se hace durante la instalación. Si todos los tiles tienen el mismo tamaño, por ejemplo, la rutina puede utilizar ese valor común sin leer un tamaño distinto para cada pieza.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: datos de los efectos ===&lt;br /&gt;
&lt;br /&gt;
Un archivo PaletteEffect contiene una lista de cambios de color. La instalación les asigna IDs y guarda sus datos en &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Como en las tablas de poses, los datos de cada efecto mantienen la misma posición en las distintas listas. Los IDs de efectos comienzan en 1; el ID 0 se utiliza para indicar que no hay efecto global. En la tabla, &#039;&#039;&#039;E&#039;&#039;&#039; es la cantidad de efectos instalados; el conjunto ocupa &#039;&#039;&#039;2 + 7 × E bytes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parte de la tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || 2 || 2 || La cantidad de efectos instalados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || E || 1 || El tipo de cada efecto, por ejemplo &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Indica qué cálculo debe realizarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || E por tabla; 3 × E entre las tres || 1 por tabla || Los valores de los canales que utiliza el efecto. En una transición, estos tres bytes guardan la dirección de la paleta de destino, no valores de canales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || E por tabla; 3 × E entre las tres || 1 por tabla || Cuánto se aplica el cambio en cada componente. Van de 0 a 127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Si el efecto es una transición hacia otra paleta, la herramienta también prepara esa paleta. Convierte sus colores al formato RGB o HSL que necesita la transición y los guarda en ROM. Durante el juego se puede utilizar ese destino sin tener que convertirlo de nuevo en cada llamada.&lt;br /&gt;
&lt;br /&gt;
Estas paletas de transición son distintas de las paletas normales que se cargan a CGRAM: contienen tres componentes por color y se utilizan para calcular el efecto.&lt;br /&gt;
&lt;br /&gt;
=== Cómo encuentra el código los recursos instalados ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; publica los IDs, direcciones, tamaños y offsets que necesitan los recursos. Por ejemplo, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifica una pose y &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifica el primer efecto de un archivo.&lt;br /&gt;
&lt;br /&gt;
Los nombres se normalizan en PascalCase: se eliminan separadores como espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra. &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, por ejemplo, pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También se genera &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, que guarda las direcciones de los bloques donde se insertaron los recursos. Cada dirección ocupa 3 bytes y se añade un valor final &amp;lt;code&amp;gt;$FFFFFF&amp;lt;/code&amp;gt; de otros 3 bytes. Para B bloques, ocupa &amp;lt;code&amp;gt;3 × (B + 1)&amp;lt;/code&amp;gt; bytes. La herramienta utiliza esa información para localizar los datos de una instalación anterior al reinstalar.&lt;br /&gt;
&lt;br /&gt;
Una reinstalación puede cambiar IDs y direcciones. Por eso hay que volver a insertar los sprites, bloques y códigos UberASM que utilizan los defines generados.&lt;br /&gt;
&lt;br /&gt;
== El trabajo de cada frame ==&lt;br /&gt;
&lt;br /&gt;
En la lógica principal se ejecutan el jugador, los sprites y los demás códigos del modo de juego. Los que utilizan Dynamic Xtreme solicitan las poses y paletas que necesitan, preparan los efectos locales y llaman a las rutinas de dibujo. Las cargas que se aceptan quedan anotadas para transferir sus datos durante NMI.&lt;br /&gt;
&lt;br /&gt;
Al terminar esa lógica, el código de game mode de Dynamic Xtreme realiza las tareas que correspondan a las opciones habilitadas: prepara las actualizaciones de VRAM de la optimización de Kevin, mantiene el estado de las paletas y calcula los efectos globales pendientes.&lt;br /&gt;
&lt;br /&gt;
Después, durante NMI, se ejecutan las transferencias preparadas: los gráficos se copian a VRAM y los colores a CGRAM. También se reinicia el contador de datos y se actualizan los relojes del sistema para el siguiente ciclo de trabajo.&lt;br /&gt;
&lt;br /&gt;
El orden que seguiremos para explicarlo es, por tanto, &#039;&#039;&#039;lógica principal → tareas al terminar el game mode → transferencias durante NMI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Lógica principal ===&lt;br /&gt;
&lt;br /&gt;
Cada recurso decide qué necesita. Un sprite puede cambiar de pose, una animación puede pedir nuevos gráficos y un código UberASM puede cargar una paleta o seleccionar un efecto.&lt;br /&gt;
&lt;br /&gt;
Si la pose solicitada ya está cargada, Dynamic Xtreme actualiza su tiempo de último uso para protegerla del reemplazo y no vuelve a cargar sus gráficos. Si no está cargada, comprueba el presupuesto de datos del frame y busca espacio disponible en VRAM antes de preparar su carga.&lt;br /&gt;
&lt;br /&gt;
El dibujo también se prepara en esta parte: las rutinas escriben en los buffers OAM la posición, los tiles y las propiedades de las piezas que se mostrarán.&lt;br /&gt;
&lt;br /&gt;
Una solicitud puede rechazarse, por ejemplo si no queda presupuesto para sus datos. El recurso que la pidió debe comprobar el resultado y decidir si conserva lo anterior o vuelve a intentarlo después. Una carga rechazada no queda guardada automáticamente para otro frame.&lt;br /&gt;
&lt;br /&gt;
=== Tareas de game mode ===&lt;br /&gt;
&lt;br /&gt;
En esta parte se realizan las siguientes tareas, según las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antes de ejecutar la lógica del juego:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitado &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;, se ejecuta la rutina del control aquí en lugar de hacerlo en NMI.&lt;br /&gt;
# Se comprueba si Dynamic Xtreme debe funcionar en el game mode actual. Si no debe hacerlo, se reinician sus variables. Esto ocurre cada frame que se permanezca en un modo no permitido.&lt;br /&gt;
&lt;br /&gt;
Después se ejecuta la lógica normal del juego, incluidos los sprites y los códigos que solicitan cargas o cambios de paleta.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cuando termina esa lógica:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitada la optimización de VRAM de Kevin, se ajustan los destinos de las actualizaciones de Lunar Magic antes de que se transfieran.&lt;br /&gt;
# Se ponen en 0 los indicadores de actualización de las paletas y se resta 1 a sus temporizadores de protección si todavía son mayores que 0. Esta parte se omite durante la pausa y en los modos no permitidos.&lt;br /&gt;
# Se aplican los efectos globales a las paletas que necesitan actualizarse y se preparan las transferencias de sus colores. Esta parte también se omite si la comprobación anterior impide continuar.&lt;br /&gt;
&lt;br /&gt;
Las copias a VRAM y CGRAM se realizan después, durante NMI. Aquí se deja preparado lo que se va a copiar.&lt;br /&gt;
&lt;br /&gt;
=== Transferencias durante NMI ===&lt;br /&gt;
&lt;br /&gt;
NMI es una interrupción que SNES puede generar al comenzar VBlank, después de dibujar la parte visible de la pantalla. El juego aprovecha ese intervalo para actualizar gráficos, colores y otros datos de video.&lt;br /&gt;
&lt;br /&gt;
En los modos permitidos, la rutina de Dynamic Xtreme reinicia &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; y actualiza sus relojes. Después ejecuta las transferencias de gráficos pendientes y luego las de paletas. Si corresponde, también actualiza el color 0,0 preparado por el sistema de efectos.&lt;br /&gt;
&lt;br /&gt;
Para realizar las copias se utiliza DMA. NMI lee cada carga de las listas, configura desde dónde se copiarán los datos, cuántos bytes se copiarán y dónde se colocarán, y ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
El tiempo de VBlank es limitado y SMW también lo necesita para sus actualizaciones de pantalla. Para limitar la cantidad de datos enviados en un frame y evitar flickering, Dynamic Xtreme utiliza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, que cuenta los bytes de las cargas solicitadas, y &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, que establece el límite permitido. Antes de aceptar una carga normal, se comprueba que sus bytes no hagan superar ese límite.&lt;br /&gt;
&lt;br /&gt;
==== Las listas de transferencias ====&lt;br /&gt;
&lt;br /&gt;
Cada transferencia guarda el origen de los datos, su banco, la cantidad de bytes y el destino en VRAM o CGRAM.&lt;br /&gt;
&lt;br /&gt;
Al realizar las copias, NMI recorre las listas desde la última entrada hacia la primera y después las vacía. Esto no borra los gráficos o colores cargados: permanecen en su destino hasta que otro código los cambie.&lt;br /&gt;
&lt;br /&gt;
La lista de VRAM utiliza 0 cuando no tiene entradas. La de CGRAM utiliza &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, porque guarda el índice de la última entrada en lugar de guardar directamente su cantidad.&lt;br /&gt;
&lt;br /&gt;
Si dos códigos escriben sobre el mismo destino, deben coordinar sus cargas. El orden de las solicitudes no debe utilizarse como sustituto de decidir qué recurso puede ocupar cada espacio.&lt;br /&gt;
&lt;br /&gt;
Normalmente, el recurso se lee desde ROM. Si el recurso se encuentra en un buffer en RAM, el usuario debe conservar su contenido hasta que NMI realice la transferencia. Por ejemplo, si prepara una paleta en RAM, no debe modificar ni reutilizar ese buffer antes de que se copie. La lista guarda su dirección, no una copia de sus datos; Dynamic Xtreme no protege el buffer contra cambios realizados por otros códigos.&lt;br /&gt;
&lt;br /&gt;
==== Presupuesto de datos ====&lt;br /&gt;
&lt;br /&gt;
Las macros de transferencia, como &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt;, comprueban cuántos bytes se han solicitado mediante &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;. Si al añadir la nueva carga se supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, la rechazan. Si la aceptan, suman sus bytes al contador.&lt;br /&gt;
&lt;br /&gt;
El límite predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Su objetivo es evitar flickering por enviar demasiados datos en un mismo frame. Es un límite de cantidad de datos, no una medida exacta del tiempo que tarda cada transferencia.&lt;br /&gt;
&lt;br /&gt;
Estas macros tienen variantes como &amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ForcedTransferToCGRAM()&amp;lt;/code&amp;gt;, que aceptan la carga sin comprobar si supera el límite. Sus bytes también se suman a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, por lo que reducen lo que queda disponible para las siguientes cargas normales. Se utilizan para cargas prioritarias, como las del jugador; usarlas no evita el flickering si se solicita una cantidad excesiva de datos.&lt;br /&gt;
&lt;br /&gt;
==== Los dos relojes ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_Timer: protección de las solicitudes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza cuando se ejecuta la parte de NMI de Dynamic Xtreme. Además de medir cuánto lleva una pose sin utilizarse, sirve para evitar que un recurso repita sus solicitudes antes de que se procesen las anteriores.&lt;br /&gt;
&lt;br /&gt;
No siempre hay un ciclo de lógica por cada ejecución completa de NMI. Durante slowdown, SMW puede ejecutar una versión reducida de NMI, y puede haber dos ciclos de lógica sin que entre ellos se hayan procesado las listas de transferencias de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Sin una protección, un recurso podría añadir otra vez sus cargas a esas listas. Las solicitudes repetidas ocuparían más espacio y podrían provocar flickering.&lt;br /&gt;
&lt;br /&gt;
Para evitarlo, las rutinas con esta protección comparan &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; con un valor guardado por el recurso, normalmente llamado &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt;. Si coinciden, el recurso ya hizo su intento con ese valor del reloj y no debe añadir de nuevo las cargas. Si son distintos, guarda el valor actual y puede realizar la nueva solicitud.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; continúa avanzando durante la pausa cuando se ejecuta esa parte de NMI.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_SyncTimer: animaciones sincronizadas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
La función principal de &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; es dar a los sprites un reloj común para sus animaciones. Por ejemplo, varios sprites que utilizan las mismas poses pueden calcular con este reloj qué pose les corresponde cada cuatro frames.&lt;br /&gt;
&lt;br /&gt;
Así todos cambian al mismo tiempo y solicitan la misma pose. La primera solicitud puede necesitar cargarla; las demás la reutilizan sin programar otra carga de sus gráficos. Esto ahorra transferencias DMA y datos enviados por frame.&lt;br /&gt;
&lt;br /&gt;
Si cada sprite llevara un reloj independiente, podrían terminar usando poses distintas de la misma animación al mismo tiempo y necesitar más cargas y espacio de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; se detiene durante la pausa y cuando se congela la acción, para que las animaciones sincronizadas también se detengan.&lt;br /&gt;
&lt;br /&gt;
== Carga de gráficos: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; guarda en RAM una lista de solicitudes de carga. Durante NMI se recorren esas solicitudes y se copian sus datos a VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Variables de la lista ===&lt;br /&gt;
&lt;br /&gt;
En esta tabla, &#039;&#039;&#039;V&#039;&#039;&#039; es el valor de &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt;: 64 por defecto. Las cuatro tablas de solicitudes reservan V bytes cada una; con entradas de 2 bytes, ese valor deja espacio para 32 solicitudes. Junto con el contador, reservan &amp;lt;code&amp;gt;1 + 4 × V&amp;lt;/code&amp;gt; bytes: 257 por defecto.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de solicitudes pendientes. El valor 0 indica que la lista está vacía.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Dirección de origen de cada solicitud, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 reservados; banco de 1 byte || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Cantidad de bytes que se copiarán.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Dirección de destino en VRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las tablas mantienen el mismo orden: la primera entrada de cada tabla pertenece a la primera solicitud, la segunda a la segunda, etc. Cada entrada de estas tablas ocupa 2 bytes, por lo que se avanza con desplazamientos de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt;, etc.&lt;br /&gt;
&lt;br /&gt;
Estos nombres representan direcciones de RAM calculadas en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus direcciones pueden cambiar según la configuración y las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
=== Añadir una solicitud ===&lt;br /&gt;
&lt;br /&gt;
La macro &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; realiza los siguientes pasos:&lt;br /&gt;
&lt;br /&gt;
# Calcula cuántos bytes habría en total al añadir la nueva carga a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Compara el resultado con &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;. Si lo supera, devuelve el carry desactivado y no añade la solicitud.&lt;br /&gt;
# Utiliza &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para encontrar la siguiente entrada y aumenta ese contador en 1.&lt;br /&gt;
# Guarda el origen, banco, cantidad de bytes y destino en las tablas.&lt;br /&gt;
# Actualiza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; con los bytes de la carga y devuelve el carry activado.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; guarda los mismos datos, pero no comprueba el límite de bytes. Las variantes &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; facilitan obtener el origen desde una dirección completa o desde los defines de un recurso.&lt;br /&gt;
&lt;br /&gt;
Añadir una solicitud no copia los gráficos inmediatamente: deja la información preparada para NMI.&lt;br /&gt;
&lt;br /&gt;
=== Ejecutar las solicitudes durante NMI ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Lee &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;. Si es 0, termina porque no hay solicitudes.&lt;br /&gt;
# Calcula el desplazamiento de la última entrada: &amp;lt;code&amp;gt;(Length - 1) × 2&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Lee su origen, banco y cantidad de bytes, y los coloca en los registros de DMA.&lt;br /&gt;
# Escribe el destino de VRAM en &amp;lt;code&amp;gt;$2116-$2117&amp;lt;/code&amp;gt; e inicia la transferencia mediante &amp;lt;code&amp;gt;$420B&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Retrocede 2 bytes para procesar la solicitud anterior. Repite hasta completar la primera.&lt;br /&gt;
# Escribe 0 en &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para indicar que la lista está vacía.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;La lista se ejecuta del final al inicio.&#039;&#039;&#039; No hace falta borrar todos sus datos al terminar: al quedar su largo en 0, la próxima solicitud volverá a utilizar la primera entrada.&lt;br /&gt;
&lt;br /&gt;
=== Animaciones con un destino fijo ===&lt;br /&gt;
&lt;br /&gt;
El código de una animación debe:&lt;br /&gt;
&lt;br /&gt;
# Elegir la imagen que corresponde al paso actual.&lt;br /&gt;
# Calcular su dirección de origen.&lt;br /&gt;
# Solicitar la copia al destino de VRAM de la animación.&lt;br /&gt;
# Comprobar el carry. Si se rechaza la carga, conservar la imagen anterior y volver a intentarlo.&lt;br /&gt;
&lt;br /&gt;
El destino puede ser siempre el mismo. Lo que cambia es la imagen que se copia allí; la lista de transferencias no decide cuándo debe avanzar la animación.&lt;br /&gt;
&lt;br /&gt;
Puedes ver un código completo en [[es/Dynamic_Xtreme_UberASM_guide#Crear_animaciones_de_gráficos|Crear animaciones de gráficos de la guía de UberASM]].&lt;br /&gt;
&lt;br /&gt;
=== Carga de una pose dinámica ===&lt;br /&gt;
&lt;br /&gt;
La carga de una pose utiliza la caché para no repetir transferencias de gráficos que ya están disponibles:&lt;br /&gt;
&lt;br /&gt;
# Busca el ID en la tabla hash.&lt;br /&gt;
# Si ya está registrado, actualiza su tiempo de uso y no añade otra carga.&lt;br /&gt;
# Si no está, comprueba la cantidad de bytes y busca un espacio adecuado en el mapa de VRAM.&lt;br /&gt;
# Elige qué poses pueden reemplazarse, teniendo en cuenta su tiempo sin uso y el espacio que necesita la nueva.&lt;br /&gt;
# Actualiza las tablas de la caché y el mapa.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; divide los datos de la pose en las transferencias necesarias.&lt;br /&gt;
# NMI ejecuta esas transferencias.&lt;br /&gt;
&lt;br /&gt;
Cada paso se desarrolla en [[#Sprites_dinámicos:_DynamicPoses|Sprites dinámicos: DynamicPoses]], incluyendo la búsqueda por hash, el mapa, la política de reemplazo y la división de la carga en filas.&lt;br /&gt;
&lt;br /&gt;
== Carga y asignación de paletas: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
El sistema distingue dos valores:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID de paleta:&#039;&#039;&#039; identifica los colores guardados en ROM.&lt;br /&gt;
* &#039;&#039;&#039;Destino de pantalla:&#039;&#039;&#039; indica qué paleta de CGRAM utilizará esos colores.&lt;br /&gt;
&lt;br /&gt;
La asignación automática permite compartir colores entre sprites sin exigir un destino fijo para cada uno.&lt;br /&gt;
&lt;br /&gt;
=== Lista de cargas a CGRAM ===&lt;br /&gt;
&lt;br /&gt;
En esta tabla, &#039;&#039;&#039;C&#039;&#039;&#039; es &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt;: 64 por defecto. El conjunto reserva &amp;lt;code&amp;gt;1 + 7 × C&amp;lt;/code&amp;gt; bytes, es decir, 449 con ese valor. Aunque &amp;lt;code&amp;gt;SourceBNK&amp;lt;/code&amp;gt; reserva 2 × C bytes, el código utiliza un byte de banco por solicitud.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Índice de la última solicitud pendiente. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; indica una lista vacía; 0 indica que hay una solicitud.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || 2 × C; 128 por defecto || 2 || Dirección de origen, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || 2 × C; 128 reservados por defecto || 1 utilizado por solicitud || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || 2 × C; 128 por defecto || 2 || Cantidad de bytes que se copiarán. Cada color ocupa 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || C; 64 por defecto || 1 || Primer color de destino en CGRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Durante NMI, &amp;lt;code&amp;gt;CGRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Comienza por la última solicitud pendiente.&lt;br /&gt;
# Configura DMA con el origen y la cantidad de bytes de esa solicitud.&lt;br /&gt;
# Selecciona el primer color mediante &amp;lt;code&amp;gt;$2121&amp;lt;/code&amp;gt; y realiza la copia.&lt;br /&gt;
# Continúa con las solicitudes anteriores.&lt;br /&gt;
# Al terminar, escribe &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; también actualizan las copias de colores y el estado de efectos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Sin efecto global:&#039;&#039;&#039; solicitan la carga y actualizan los buffers de SMW. Así el juego no vuelve a utilizar colores anteriores durante la animación de victoria del goal.&lt;br /&gt;
* &#039;&#039;&#039;Con efecto global:&#039;&#039;&#039; guardan los colores originales y preparan el estado necesario para aplicarles el efecto antes de enviarlos a CGRAM.&lt;br /&gt;
&lt;br /&gt;
=== Asignación automática ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 32 || 2 || Guarda el ID asignado a cada destino. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre y &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; una reservada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 16 || 1 || Protege cada destino del reemplazo automático mientras está en uso.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta de sprites || Indica qué paletas de sprites están asignadas con efecto global habilitado. Esta condición también se compara al compartir una asignación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue este orden:&lt;br /&gt;
&lt;br /&gt;
# Reutilizar una asignación con el mismo ID y una condición de efecto compatible.&lt;br /&gt;
# Si no existe, utilizar una entrada libre.&lt;br /&gt;
# Si no hay entradas libres, reemplazar una que no esté reservada y cuyo temporizador sea 0.&lt;br /&gt;
# Si no encuentra ninguna, indicar que la asignación falló.&lt;br /&gt;
&lt;br /&gt;
Mientras el recurso utiliza la paleta, mantiene su temporizador en 2. Llegar a 0 no borra los colores: la asignación puede reutilizarse si otro recurso todavía no la reemplazó.&lt;br /&gt;
&lt;br /&gt;
=== Asignación manual y versión ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Manual con carga:&#039;&#039;&#039; el código elige el destino y solicita sus colores.&lt;br /&gt;
* &#039;&#039;&#039;Manual sin carga:&#039;&#039;&#039; el código elige el destino y utiliza los colores que ya estaban preparados.&lt;br /&gt;
* &#039;&#039;&#039;Versión:&#039;&#039;&#039; selecciona una entrada de la lista de paletas del DynamicInfo. La última versión procesada permite comprobar si esa selección cambió.&lt;br /&gt;
&lt;br /&gt;
Dos recursos que elijan el mismo destino con colores distintos deben coordinarse. Mantener la protección de una paleta no significa volver a cargar sus colores.&lt;br /&gt;
&lt;br /&gt;
== Dibujo de poses: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
El dibujo prepara las piezas de una pose en OAM: qué tiles se muestran, dónde se colocan y qué propiedades utilizan. Los datos gráficos deben estar en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Pasos del dibujo ===&lt;br /&gt;
&lt;br /&gt;
# Busca la rutina y los datos de la pose mediante &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Obtiene la cantidad de piezas desde &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Calcula la posición de cada tile usando la posición del sprite, sus desplazamientos y los volteos que correspondan.&lt;br /&gt;
# Comprueba si la pieza puede verse y si queda espacio de OAM.&lt;br /&gt;
# Escribe su posición, número de tile, propiedades y tamaño en los buffers OAM.&lt;br /&gt;
&lt;br /&gt;
El número de tile depende del dibujo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Cómo se obtiene el tile&lt;br /&gt;
|-&lt;br /&gt;
| Pose dinámica || Se ajusta al lugar de VRAM donde quedaron cargados sus gráficos.&lt;br /&gt;
|-&lt;br /&gt;
| Pose estática || Se utiliza su número de tile fijo.&lt;br /&gt;
|-&lt;br /&gt;
| Pose que utiliza un tile común || El código debe preparar &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; antes de llamar al dibujo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Prioridad y espacio disponible ===&lt;br /&gt;
&lt;br /&gt;
* En &#039;&#039;&#039;LoROM&#039;&#039;&#039;, el sistema lleva su propio control de entradas OAM disponibles.&lt;br /&gt;
* En &#039;&#039;&#039;SA-1&#039;&#039;&#039;, utiliza la integración con MaxTile.&lt;br /&gt;
* La &#039;&#039;&#039;prioridad de dibujo&#039;&#039;&#039; organiza las piezas de sprites. No es la misma propiedad que determina si un tile queda delante o detrás de las capas.&lt;br /&gt;
* Los &#039;&#039;&#039;límites por línea de pantalla&#039;&#039;&#039; de SNES siguen existiendo. Tener una pose cargada no garantiza que puedan verse todas sus piezas.&lt;br /&gt;
&lt;br /&gt;
== Jugador y Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
El jugador original tiene rutinas propias para elegir y cargar las piezas de sus poses. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; permite integrar ese trabajo con las cargas de Dynamic Xtreme y cambiar el origen de sus gráficos y paletas.&lt;br /&gt;
&lt;br /&gt;
Con el formato original, el juego sigue eligiendo las piezas de la pose. La rutina obtiene sus direcciones desde el origen configurado y compara esas direcciones con las anteriores para cargar las que hayan cambiado.&lt;br /&gt;
&lt;br /&gt;
Estas cargas utilizan transferencias forzadas y sus bytes también cuentan para las solicitudes normales posteriores. Así conservan su prioridad sin quedar fuera de la contabilidad del sistema.&lt;br /&gt;
&lt;br /&gt;
La paleta del jugador tiene un tratamiento especial: combina colores y selecciones del propio juego con el origen personalizado. No funciona simplemente como sustituir una paleta completa de un sprite cualquiera.&lt;br /&gt;
&lt;br /&gt;
El soporte para jugadores personalizados permite que otros sistemas administren de otra forma sus poses y dibujo. No convierte automáticamente cualquier spritesheet al formato del jugador original.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi también carga sus gráficos por piezas. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; permite cambiar su origen manteniendo la organización que esperan sus rutinas.&lt;br /&gt;
&lt;br /&gt;
El código calcula qué partes necesita y prepara sus cargas a los destinos correspondientes de VRAM. Como las del jugador, estas cargas tienen un tratamiento prioritario.&lt;br /&gt;
&lt;br /&gt;
Esta opción necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad. No permite evitar un conflicto del sistema del jugador habilitando únicamente las funciones de Yoshi.&lt;br /&gt;
&lt;br /&gt;
== Memoria y optimizaciones ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW mantiene en RAM gráficos originales del jugador, Yoshi y ciertas animaciones. En ROMs sin SA-1, esta opción adapta las cargas para leer esos datos desde ROM.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aprovecha la RAM recuperada para sus variables internas. No es un espacio que quede libre para que cualquier otro código escriba encima.&lt;br /&gt;
&lt;br /&gt;
SA-1 utiliza otras direcciones y desactiva esta opción. Los rangos están en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
Esta opción mueve el procesamiento del control desde NMI a la parte de game mode. El objetivo es dejar más tiempo para las actualizaciones de pantalla, no añadir un frame de retraso ni cambiar los botones que recibe el juego.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
El color fijo se utiliza en las mezclas de color de la consola. Para actualizarlo, el juego prepara sus componentes y los envía al registro correspondiente.&lt;br /&gt;
&lt;br /&gt;
La optimización reemplaza esa preparación por una secuencia más corta. El color sigue enviándose a la consola, pero necesita menos trabajo durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic utiliza listas llamadas stripe images para actualizar partes de los mapas de tiles. Esas listas incluyen tanto los datos como la información sobre sus destinos.&lt;br /&gt;
&lt;br /&gt;
La versión integrada de la optimización de Kevin prepara fuera de NMI parte del ajuste de esos destinos. Así deja menos trabajo de preparación para el momento de la transferencia.&lt;br /&gt;
&lt;br /&gt;
Esta opción sustituye el uso del parche original por separado. Además, no debe desinstalarse después de instalarla; hay que tenerlo en cuenta antes de activarla.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
La barra de estado original actualiza zonas concretas de VRAM. Esta opción prepara sus transferencias de forma más directa, reduciendo la configuración de DMA que necesita hacer durante NMI.&lt;br /&gt;
&lt;br /&gt;
No añade una barra nueva. Modifica la actualización de la original y, por eso, entra en conflicto con recursos que la reemplazan, modifican o eliminan.&lt;br /&gt;
&lt;br /&gt;
== Sprites dinámicos: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
El sistema funciona como una &#039;&#039;&#039;caché de poses en VRAM&#039;&#039;&#039;. No reserva una copia de los gráficos para cada sprite: guarda la pose y permite que la reutilicen todos los recursos que la necesiten.&lt;br /&gt;
&lt;br /&gt;
* Una pose se carga una sola vez mientras permanezca en la caché.&lt;br /&gt;
* Las siguientes solicitudes actualizan su tiempo de último uso, sin añadir otra carga de sus gráficos.&lt;br /&gt;
* La pose no se borra cuando un recurso deja de utilizarla. Permanece allí hasta que se necesite su espacio y se elija reemplazarla.&lt;br /&gt;
* Si fue reemplazada y vuelve a solicitarse, tendrá que cargarse otra vez.&lt;br /&gt;
&lt;br /&gt;
La elección no depende de cuánto tiempo lleva la pose desde que se cargó, sino de &#039;&#039;&#039;cuánto tiempo lleva sin utilizarse&#039;&#039;&#039; y de si su espacio sirve para la pose nueva.&lt;br /&gt;
&lt;br /&gt;
=== Tres valores distintos ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Qué identifica&lt;br /&gt;
|-&lt;br /&gt;
| ID de pose || La pose instalada. Tiene 16 bits y permite consultar sus datos en ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Índice de la tabla hash || La entrada de RAM donde se registró la pose. Va de 0 a 127.&lt;br /&gt;
|-&lt;br /&gt;
| Bloque de VRAM || ID de una de las 128 posiciones para tiles de 16×16 que caben en el espacio de VRAM de sprites. Se numeran de izquierda a derecha y de arriba abajo, desde 0 hasta 127. Para una pose que ocupa varios bloques, se guarda el ID de su primer bloque.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
El índice de la tabla hash y el bloque de VRAM no tienen por qué coincidir. Una entrada de la tabla puede registrar una pose que empieza en cualquier bloque permitido.&lt;br /&gt;
&lt;br /&gt;
=== Tablas de las poses registradas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de poses registradas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 || 1 || Cantidad de poses registradas para cada hash.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 256 || 2 || ID completo de la pose de cada entrada. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Bloque de VRAM donde comienza cada pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 256 || 2 || Valor de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; de su último uso.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas ocupan &#039;&#039;&#039;769 bytes&#039;&#039;&#039; en RAM. Guardan las poses registradas durante el juego; las tablas generadas desde el DynamicInfo describen, en cambio, todas las poses instaladas.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se busca una pose ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;DynamicPoseHashmap_FindPose&amp;lt;/code&amp;gt; utiliza una tabla hash de 128 entradas. El hash permite elegir dónde empezar a buscar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hash = ID de pose AND $007F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dos IDs diferentes pueden tener el mismo hash. Por ejemplo, &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; producen &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;. Por eso el hash no basta para confirmar que la pose está cargada: también se compara el ID completo.&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue estos pasos:&lt;br /&gt;
&lt;br /&gt;
# Guarda el ID solicitado y calcula su hash.&lt;br /&gt;
# Si &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; es 0, no hay poses registradas y la búsqueda termina.&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize[hash]&amp;lt;/code&amp;gt;. Si es 0, ninguna pose registrada tiene ese hash y también termina.&lt;br /&gt;
# Comienza por la entrada cuyo índice coincide con el hash.&lt;br /&gt;
# Lee el ID de esa entrada. Si coincide con el solicitado, encontró la pose.&lt;br /&gt;
# Si no coincide, continúa con la siguiente entrada de la secuencia de búsqueda.&lt;br /&gt;
&lt;br /&gt;
La secuencia avanza &#039;&#039;&#039;15 entradas por intento&#039;&#039;&#039; y vuelve al comienzo al superar 127:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
siguiente índice = (índice actual + 15) AND $7F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Con 128 entradas, ese paso permite visitar todas las posiciones antes de repetir una. Para el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, el comienzo de la secuencia es:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$05 → $14 → $23 → $32 → $41 → ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== El contador de poses de cada hash ====&lt;br /&gt;
&lt;br /&gt;
Cada hash tiene su propio contador en &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt;. Por ejemplo, si hay dos poses registradas cuyo ID produce el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, la entrada &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize+$05&amp;lt;/code&amp;gt; contiene 2.&lt;br /&gt;
&lt;br /&gt;
Ese número indica &#039;&#039;&#039;cuántas poses con ese hash existen&#039;&#039;&#039;, no cuántas posiciones hay que recorrer. La búsqueda utiliza una copia temporal del contador:&lt;br /&gt;
&lt;br /&gt;
# Comienza con la cantidad de poses registrada para el hash solicitado.&lt;br /&gt;
# Recorre las posiciones de la secuencia hasta encontrar el ID solicitado o haber comprobado esa cantidad de poses con el mismo hash.&lt;br /&gt;
# Cada vez que encuentra una pose con ese hash, pero con otro ID, resta 1 al contador temporal.&lt;br /&gt;
# Las posiciones libres y las poses de otros hashes no descuentan nada: continúa buscando.&lt;br /&gt;
# Si el contador temporal llega a 0 sin encontrar el ID, la pose solicitada no está registrada y la búsqueda termina.&lt;br /&gt;
&lt;br /&gt;
El contador de &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; no se modifica durante esta búsqueda. Solo se actualiza al añadir o retirar poses de la caché.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, se busca &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt;, que produce el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, y el contador de ese hash vale 2:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Posición visitada !! ID guardado !! Hash del ID !! Poses del hash $05 que faltan por comprobar&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 1: tiene el mismo hash, pero no es el ID solicitado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0014&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || 1: es otro hash, así que no se descuenta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$23&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || 0: ya se comprobaron las dos poses con ese hash. &amp;lt;code&amp;gt;$0105&amp;lt;/code&amp;gt; no está registrada.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Lo habitual es que haya una o dos poses por hash. Esto permite resolver la búsqueda con pocas comprobaciones y un coste normalmente cercano a &amp;lt;code&amp;gt;O(1)&amp;lt;/code&amp;gt;. No significa que siempre se visiten solo una o dos posiciones: puede haber entradas de otros hashes entre ellas. Con muchas colisiones, el recorrido puede ser más largo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Una entrada libre no termina la búsqueda.&#039;&#039;&#039; Puede haber quedado vacía al reemplazar una pose y existir otra del mismo hash más adelante. El contador permite saber cuándo ya se comprobaron todas las poses de ese hash, incluso si hay huecos entre ellas.&lt;br /&gt;
&lt;br /&gt;
==== Cuando encuentra la pose ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Obtiene el índice de la entrada encontrada.&lt;br /&gt;
# Escribe el valor actual de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; para esa entrada.&lt;br /&gt;
# Devuelve el éxito de la solicitud, sin volver a programar la carga de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
Así todos los recursos que solicitan ese ID utilizan la misma pose y la mantienen protegida. No importa si el recurso es un sprite normal, cluster, extended u otro código que utiliza el sistema.&lt;br /&gt;
&lt;br /&gt;
Esto también evita duplicar una carga dentro del mismo ciclo: cuando la primera solicitud se acepta, la pose ya queda registrada aunque la transferencia física se vaya a realizar durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== Cuando la pose no está registrada ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt; continúa con la preparación de una carga nueva:&lt;br /&gt;
&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; y calcula &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend + PoseSize&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, termina con fallo, sin cambiar las poses existentes.&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; para saber cuántos bloques necesita.&lt;br /&gt;
# Llama a &amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; para buscar un espacio adecuado.&lt;br /&gt;
# Si no existe un espacio utilizable, termina con fallo.&lt;br /&gt;
# Retira del mapa y de la tabla hash las poses que ocupen el espacio elegido.&lt;br /&gt;
# Busca una entrada libre de la tabla hash y registra la pose nueva.&lt;br /&gt;
# Actualiza el mapa de VRAM y el contador de datos del frame.&lt;br /&gt;
# Llama a &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; para añadir las transferencias.&lt;br /&gt;
&lt;br /&gt;
El presupuesto se comprueba antes de reemplazar poses. Si la nueva carga no cabe en el frame, no se libera espacio para una solicitud que no se puede atender.&lt;br /&gt;
&lt;br /&gt;
==== Añadir y quitar entradas de la tabla hash ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_FindFreeSpace&amp;lt;/code&amp;gt; busca una entrada cuyo ID sea &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt;, siguiendo la misma secuencia de pasos de 15.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; guarda el ID y su tiempo de uso, aumenta &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; y aumenta el contador de su hash.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Remove&amp;lt;/code&amp;gt; escribe &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; en el ID retirado y reduce ambos contadores.&lt;br /&gt;
&lt;br /&gt;
Retirar una entrada no borra por sí solo los píxeles de VRAM. Indica que esa pose dejó de estar disponible en la caché; las nuevas transferencias sobrescribirán el espacio elegido.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se representa el mapa de VRAM ===&lt;br /&gt;
&lt;br /&gt;
El mapa tiene &#039;&#039;&#039;128 bloques&#039;&#039;&#039; de gráficos de 16×16. En 4bpp, un bloque completo equivale a 128 bytes de gráficos. Las poses incompletas pueden copiar menos datos, pero necesitan reservar los bloques que ocupan.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Bloque donde comienza la región. El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica que está reservada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt;, también llamada &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 || 1 || Si el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; está activo, los otros bits guardan el tamaño de la región libre menos uno. Si está desactivado, guardan el índice de la pose en la tabla hash.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Son &#039;&#039;&#039;256 bytes&#039;&#039;&#039; adicionales. Junto con las tablas de poses, el administrador utiliza &#039;&#039;&#039;1025 bytes&#039;&#039;&#039; de RAM, sin contar las listas de DMA ni las scratch de trabajo.&lt;br /&gt;
&lt;br /&gt;
El mapa guarda la información en los extremos de cada región: su primer y su último bloque. No necesita mantener un registro independiente de la pose en cada bloque intermedio.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, una región libre de 6 bloques, desde &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; hasta &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;, guarda en ambos extremos:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Offset = $20&amp;lt;/code&amp;gt;: comienzo de la región.&lt;br /&gt;
* &amp;lt;code&amp;gt;Size = $85&amp;lt;/code&amp;gt;: bit de región libre &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; más el tamaño menos uno, &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Si la región está ocupada, el tamaño se obtiene consultando el ID de su entrada hash y después &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Las configuraciones de &amp;lt;code&amp;gt;DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; preparan las regiones disponibles y reservadas de SP1-SP4. Una región reservada no puede elegirse para una pose nueva.&lt;br /&gt;
&lt;br /&gt;
=== Recorrido y búsqueda de espacio ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; comienza en el bloque &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt; y recorre las regiones hacia atrás:&lt;br /&gt;
&lt;br /&gt;
# Lee el comienzo de la región desde &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Comprueba si está reservada.&lt;br /&gt;
# Obtiene su tamaño y su puntuación de tiempo sin uso.&lt;br /&gt;
# Comprueba si sirve para la pose solicitada o si debe considerar también una región contigua.&lt;br /&gt;
# Para pasar a la región anterior, utiliza &amp;lt;code&amp;gt;comienzo de la región - 1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El registro del último bloque permite saltar regiones completas. No se recorren uno por uno todos los bloques que ocupa una pose.&lt;br /&gt;
&lt;br /&gt;
Durante la búsqueda se conservan los datos del espacio que se está evaluando y del mejor encontrado:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos de trabajo !! Bytes totales !! Bytes por valor !! Para qué se usan&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapCurrentSpace&amp;lt;/code&amp;gt; || 3 || 1 por campo || Comienzo, puntuación y cantidad de bloques del candidato actual.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapBestSpace&amp;lt;/code&amp;gt; || 3 || 1 por campo || Los mismos campos para el mejor candidato encontrado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapTMP_Size&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de bloques que necesita la pose nueva.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos nombres son datos temporales en scratch, no reservas adicionales de RAM persistente.&lt;br /&gt;
&lt;br /&gt;
=== Política de reemplazo: tiempo sin uso y espacio suficiente ===&lt;br /&gt;
&lt;br /&gt;
El sistema no elige simplemente la pose que se cargó primero. Utiliza el tiempo transcurrido desde su &#039;&#039;&#039;último uso&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tiempo sin uso = DX_Timer - TimeLastUse de la pose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMapSlot_GetSizeAndScore&amp;lt;/code&amp;gt; obtiene el tamaño y una puntuación para cada región:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Puntuación y tratamiento&lt;br /&gt;
|-&lt;br /&gt;
| Región libre || &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Se favorece frente a regiones ocupadas.&lt;br /&gt;
|-&lt;br /&gt;
| Región ocupada || Tiempo sin uso, limitado a &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Tiempo sin uso de 0 o 1 || No se puede reemplazar: la pose sigue protegida.&lt;br /&gt;
|-&lt;br /&gt;
| Región reservada || Se descarta, independientemente del tiempo sin uso.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La protección exige &#039;&#039;&#039;al menos dos avances de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; sin utilizar la pose&#039;&#039;&#039;. Cada recurso que vuelve a solicitarla actualiza su tiempo de uso y vuelve a protegerla.&lt;br /&gt;
&lt;br /&gt;
==== Por qué no siempre se reemplaza la pose con más tiempo sin uso ====&lt;br /&gt;
&lt;br /&gt;
La pose nueva necesita espacio suficiente y contiguo. Un espacio pequeño no sirve por sí solo, aunque lleve mucho tiempo sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para una pose nueva de 4 bloques:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Espacio candidato !! Tiempo sin uso !! ¿Sirve?&lt;br /&gt;
|-&lt;br /&gt;
| Pose A: 2 bloques, sin espacio contiguo utilizable || 20 || No: solo deja 2 bloques.&lt;br /&gt;
|-&lt;br /&gt;
| Pose B: 4 bloques || 8 || Sí: puede alojar la pose nueva.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
En este caso se puede reemplazar B y conservar A. A lleva más tiempo sin uso, pero su espacio no permite atender la solicitud.&lt;br /&gt;
&lt;br /&gt;
Si dos o más regiones contiguas pueden reemplazarse, el sistema puede considerarlas juntas. Para esa combinación:&lt;br /&gt;
&lt;br /&gt;
* Suma sus cantidades de bloques.&lt;br /&gt;
* Utiliza la &#039;&#039;&#039;menor puntuación&#039;&#039;&#039; de las regiones combinadas, es decir, el menor tiempo sin uso.&lt;br /&gt;
* Si una está reservada o protegida, no puede utilizarla para completar el espacio.&lt;br /&gt;
&lt;br /&gt;
Así una pose usada recientemente no puede quedar sobrescrita por combinarla con otra que lleva mucho tiempo sin uso.&lt;br /&gt;
&lt;br /&gt;
==== Elegir entre candidatos válidos ====&lt;br /&gt;
&lt;br /&gt;
# El candidato debe tener al menos la cantidad de bloques solicitada.&lt;br /&gt;
# Se prefiere la puntuación más alta: espacio libre o mayor tiempo sin uso.&lt;br /&gt;
# Si las puntuaciones son iguales, se prefiere el candidato con menos bloques, siempre que la pose quepa.&lt;br /&gt;
# Si puntuación y tamaño también coinciden, se conserva el candidato que ya se había elegido.&lt;br /&gt;
&lt;br /&gt;
Las regiones se combinan durante la búsqueda cuando el candidato todavía es demasiado pequeño. No se juntan todas las regiones reemplazables sin tener en cuenta el tamaño solicitado.&lt;br /&gt;
&lt;br /&gt;
=== Reemplazar y dividir la región elegida ===&lt;br /&gt;
&lt;br /&gt;
Una vez elegido el espacio:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemovePosesInSpace&amp;lt;/code&amp;gt; recorre sus regiones y retira de la tabla hash las poses que haya que reemplazar.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemoveSpace&amp;lt;/code&amp;gt; representa el espacio elegido como una región libre, actualizando sus extremos.&lt;br /&gt;
# Se busca una entrada hash libre y se guarda el bloque de comienzo en &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; registra la pose.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_AddPoseInSpace&amp;lt;/code&amp;gt; escribe el índice hash de la pose y el comienzo de su región en el primer y último bloque.&lt;br /&gt;
# Si sobran bloques, crea otra región libre con el resto.&lt;br /&gt;
&lt;br /&gt;
Si una región de 6 bloques aloja una pose de 4, quedan una región ocupada de 4 y una libre de 2. No se mueven las demás poses para compactar VRAM.&lt;br /&gt;
&lt;br /&gt;
=== DynamicRoutine: preparar las transferencias de la pose ===&lt;br /&gt;
&lt;br /&gt;
En este punto ya se eligió el espacio y se registró la pose. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; convierte esa asignación en solicitudes de transferencia.&lt;br /&gt;
&lt;br /&gt;
Utiliza estos datos:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Dato !! Cantidad consultada por pose !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Bloque de comienzo || 1 byte || Lugar elegido por el mapa de VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; || 2 bytes de una tabla de 256 bytes || Convierte uno de los 128 bloques en un desplazamiento de VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 bytes || Dirección completa de los datos de la pose en ROM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 bytes: dos valores de 2 || Cantidad de bytes del primer y del segundo tramo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 bytes || Desplazamiento de VRAM para el segundo tramo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Convertir el bloque en una dirección de VRAM ====&lt;br /&gt;
&lt;br /&gt;
Los bloques de 16×16 no se convierten simplemente en un desplazamiento lineal de bytes. Cada uno utiliza tiles de 8×8 distribuidos en las filas de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; contempla esa distribución. Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bloque !! Desplazamiento !! Dirección de VRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas direcciones de VRAM están expresadas en palabras de 2 bytes, no en bytes. La rutina suma la base &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; utilizada para los gráficos de sprites.&lt;br /&gt;
&lt;br /&gt;
==== Procesar los tramos y sus filas ====&lt;br /&gt;
&lt;br /&gt;
# Obtiene el origen desde &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Procesa los bytes del primer tramo mediante &amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si el segundo tramo tiene tamaño 0, termina.&lt;br /&gt;
# Si existe, adelanta el origen la cantidad de bytes del primer tramo.&lt;br /&gt;
# Suma &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; al desplazamiento de VRAM y procesa el segundo tramo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt; divide cada tramo según las filas y el punto de comienzo. Para un destino V expresado en palabras de VRAM, prepara:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Final de la primera fila = (V + $0100) AND $FF00&lt;br /&gt;
Bytes hasta ese final = (final de la primera fila - V) × 2&lt;br /&gt;
Destino de la segunda parte = final de la primera fila + $0100&lt;br /&gt;
Bytes de la segunda parte de un grupo = $0200 - bytes de la primera&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los tamaños son cantidades de bytes, mientras que los destinos de VRAM están expresados en palabras. Por eso se multiplica por 2 al calcular cuántos datos caben hasta el final de una fila.&lt;br /&gt;
&lt;br /&gt;
La rutina utiliza tres recorridos:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt;: añade una solicitud final con los bytes restantes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLinesWithEndLine&amp;lt;/code&amp;gt;: añade dos solicitudes para los datos restantes, cada una con su destino y cantidad de bytes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLines&amp;lt;/code&amp;gt;: añade dos solicitudes que suman &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, avanza el origen y los destinos y repite con los datos que faltan.&lt;br /&gt;
&lt;br /&gt;
Hay un caso directo antes del recorrido general: si el destino comienza en un límite de &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; palabras y el tramo tiene al menos &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, la rutina utiliza &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt; para preparar la copia del tramo completo en una solicitud.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, un tramo de &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes que comienza en &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; se divide así:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Solicitud !! Origen !! Destino VRAM !! Bytes&lt;br /&gt;
|-&lt;br /&gt;
| Primera || Comienzo del tramo || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt;: 448&lt;br /&gt;
|-&lt;br /&gt;
| Segunda || Comienzo del tramo + &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0040&amp;lt;/code&amp;gt;: 64&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las dos solicitudes copian los 512 bytes del tramo, respetando los destinos que calcula la distribución de filas. No son dos copias completas de la pose.&lt;br /&gt;
&lt;br /&gt;
Cada solicitud utiliza estas tablas:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Por cada solicitud añadida aumenta &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
La cantidad total de bytes de la pose ya se comprobó y se añadió a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;. Esta parte divide esa carga en transferencias; no vuelve a contar la pose completa por cada solicitud.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; &#039;&#039;&#039;no ejecuta DMA&#039;&#039;&#039;. Deja las solicitudes preparadas para que &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt; las copie durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== Qué conserva el sprite ===&lt;br /&gt;
&lt;br /&gt;
Las rutinas de sprites guardan el índice hash de la pose utilizable, no una copia independiente de sus gráficos. Ese índice permite consultar su bloque de VRAM y mantener actualizado su tiempo de uso.&lt;br /&gt;
&lt;br /&gt;
Si una pose nueva no puede cargarse:&lt;br /&gt;
&lt;br /&gt;
* Si existe una pose anterior válida, se mantiene y se actualiza su tiempo de uso para protegerla.&lt;br /&gt;
* Si nunca hubo una pose válida, no se debe dibujar como si la solicitud hubiera tenido éxito.&lt;br /&gt;
* En las llamadas con soporte para mantener la anterior, el carry puede indicar que todavía hay una pose utilizable aunque no se haya completado el cambio.&lt;br /&gt;
&lt;br /&gt;
La animación y el movimiento siguen siendo responsabilidad del sprite. La caché se ocupa de reutilizar o preparar los gráficos solicitados.&lt;br /&gt;
&lt;br /&gt;
== Efectos de paleta: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
El sistema conserva los colores originales para poder cambiar de efecto, combinarlo con otro o volver a la paleta sin efecto. No debe utilizar el resultado ya afectado como si fuera la paleta original.&lt;br /&gt;
&lt;br /&gt;
=== Buffers de colores ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o buffer !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 || 2 por color || Colores de base en formato SNES, con 2 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 || 3 por color || Base separada en rojo, verde y azul, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 || 3 por color || Base separada en tono, saturación y luminosidad, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 || 2 por color || Resultado en formato SNES, listo para solicitar su copia a CGRAM. Corresponde al buffer de paletas del juego.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Indicadores de cada paleta ===&lt;br /&gt;
&lt;br /&gt;
Cada bit de estos indicadores corresponde a una paleta. Las variables &amp;lt;code&amp;gt;BG&amp;lt;/code&amp;gt; cubren 0-7 y las &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt; cubren 8-F.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variables !! Bytes totales !! Bytes por valor !! Qué indican&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si ya se preparó la base de colores en formato SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparada la conversión de la base a RGB.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparada la conversión de la base a HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparado el resultado del efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos indicadores evitan repetir conversiones y cálculos que siguen siendo válidos.&lt;br /&gt;
&lt;br /&gt;
=== Preparar una base ===&lt;br /&gt;
&lt;br /&gt;
# Se comprueba si la paleta ya tiene una base registrada.&lt;br /&gt;
# Si no la tiene, se obtienen los colores del buffer del juego. Una carga explícita, como &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, puede proporcionar esa base directamente.&lt;br /&gt;
# Se comprueba si el efecto necesita RGB o HSL.&lt;br /&gt;
# Si falta esa conversión, se prepara y se marca como disponible.&lt;br /&gt;
&lt;br /&gt;
Si solo cambia el efecto, la base puede seguir siendo válida. Si cambian los colores originales, las llamadas de carga actualizan la base e invalidan las conversiones y resultados que deben calcularse otra vez.&lt;br /&gt;
&lt;br /&gt;
=== Datos de un efecto ===&lt;br /&gt;
&lt;br /&gt;
El ID permite consultar las tablas generadas durante la instalación:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt;: cálculo que debe realizarse.&lt;br /&gt;
* &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt;: valores de los canales o dirección de la paleta de destino de una transición.&lt;br /&gt;
* &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt;: cuánto se aplica cada cambio.&lt;br /&gt;
&lt;br /&gt;
Los canales utilizan valores de 0 a 31. Los ratios van de 0 a 127: 0 conserva el origen y 127 aplica por completo el cambio elegido.&lt;br /&gt;
&lt;br /&gt;
Los cálculos se realizan fuera de NMI. NMI realiza la transferencia de los colores resultantes.&lt;br /&gt;
&lt;br /&gt;
=== Efecto global ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Bytes totales !! Bytes por valor !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 || 2 || Selecciona el efecto global. El valor 0 permite restaurar los colores de base.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta || Selecciona las paletas 0-7 que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta || Selecciona las paletas 8-F que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 32 || 2 || Guarda el último ID global procesado por cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 || 1 || Controla la participación del color fijo y el color 0,0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para cada paleta habilitada, el administrador:&lt;br /&gt;
&lt;br /&gt;
# Comprueba si necesita actualizar el resultado del efecto.&lt;br /&gt;
# Prepara la base RGB o HSL si todavía falta.&lt;br /&gt;
# Calcula el efecto si el resultado anterior ya no sirve.&lt;br /&gt;
# Prepara los colores en formato SNES y solicita su transferencia.&lt;br /&gt;
# Confirma el ID procesado cuando la carga correspondiente se acepta.&lt;br /&gt;
&lt;br /&gt;
Si se mantiene el mismo efecto y no cambió la base, no hace falta calcularlo otra vez. Al cambiar el ID global se invalidan los resultados anteriores, no necesariamente las bases RGB y HSL.&lt;br /&gt;
&lt;br /&gt;
El ID global 0 también requiere una actualización: el sistema debe cargar de nuevo los colores de base para quitar el efecto anterior.&lt;br /&gt;
&lt;br /&gt;
=== Efecto local y concatenación ===&lt;br /&gt;
&lt;br /&gt;
Un recurso puede tener un efecto propio y recibir también el global. Por ejemplo, un sprite puede cambiar de tono y después oscurecerse junto con el nivel.&lt;br /&gt;
&lt;br /&gt;
El orden es:&lt;br /&gt;
&lt;br /&gt;
# Preparar el resultado del efecto local.&lt;br /&gt;
# Utilizarlo como base para el efecto global mediante la llamada de concatenación.&lt;br /&gt;
# Calcular el efecto global sobre esa base.&lt;br /&gt;
# Cargar el resultado combinado, sin mostrar antes la versión que solo tiene el efecto local.&lt;br /&gt;
&lt;br /&gt;
* La concatenación RGB se utiliza con efectos RGB.&lt;br /&gt;
* La concatenación HSL se utiliza con efectos HSL.&lt;br /&gt;
* Los recursos que comparten un destino de CGRAM comparten sus colores. Para mostrar dos efectos locales distintos, necesitan destinos que permitan mantener ambos resultados.&lt;br /&gt;
&lt;br /&gt;
=== Si no se acepta la transferencia ===&lt;br /&gt;
&lt;br /&gt;
* Calcular el efecto no significa que ya esté en CGRAM.&lt;br /&gt;
* Si la transferencia no se acepta, el administrador puede volver a intentar la actualización.&lt;br /&gt;
* Cuando corresponde, se mantiene el resultado anterior utilizable hasta poder sustituirlo.&lt;br /&gt;
* No se deben cargar primero los colores originales sin efecto: podrían verse así durante un frame antes del resultado correcto.&lt;br /&gt;
&lt;br /&gt;
== Cómo trabajan juntos ==&lt;br /&gt;
&lt;br /&gt;
El recorrido de un sprite dinámico reúne estas tareas:&lt;br /&gt;
&lt;br /&gt;
# Su lógica elige la pose y la versión de paleta.&lt;br /&gt;
# La asignación busca una paleta utilizable y prepara los colores si hace falta.&lt;br /&gt;
# La caché protege la pose ya cargada o prepara la carga de una nueva.&lt;br /&gt;
# El dibujo escribe los datos de sus piezas en los buffers OAM.&lt;br /&gt;
# El administrador de efectos prepara los cambios globales pendientes.&lt;br /&gt;
# NMI realiza las transferencias de gráficos y colores solicitadas.&lt;br /&gt;
&lt;br /&gt;
Compartir gráficos, compartir una paleta y compartir una rutina de dibujo son tres cosas distintas. Dynamic Xtreme puede aprovechar cada una sin obligar a que los recursos compartan también las demás.&lt;br /&gt;
&lt;br /&gt;
== Lecturas relacionadas ==&lt;br /&gt;
&lt;br /&gt;
* [[es/Dynamic_Xtreme|Artículo principal]]: funcionalidades y compatibilidad.&lt;br /&gt;
* [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_sprite_creation_guide|Creación de sprites dinámicos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_UberASM_guide|Dynamic Xtreme con UberASM]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_ASM_API|API ASM]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21373</id>
		<title>es/Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21373"/>
		<updated>2026-10-25T02:38:52Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo funciona Dynamic Xtreme, desde la preparación de los recursos al instalarlo hasta la carga y el dibujo de una pose durante el juego.&lt;br /&gt;
&lt;br /&gt;
== Qué prepara la instalación ==&lt;br /&gt;
&lt;br /&gt;
Antes de que un sprite pueda usar sus gráficos o una paleta, Dynamic Xtreme tiene que guardarlos en la ROM y preparar la información para encontrarlos. Lo mismo ocurre con cualquier otro recurso dinámico que hayas añadido.&lt;br /&gt;
&lt;br /&gt;
Para hacerlo, la herramienta lee los DynamicInfo, DrawInfo y PaletteEffect. Cada archivo aporta una parte distinta: qué recursos se van a cargar, cómo se dibujan las poses y qué cambios de color se pueden aplicar.&lt;br /&gt;
&lt;br /&gt;
Gracias a esta preparación se generan defines en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permiten utilizar los recursos y ejecutar fácilmente las rutinas necesarias.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: recursos y datos de carga ===&lt;br /&gt;
&lt;br /&gt;
Un DynamicInfo reúne los gráficos de poses, las paletas y los recursos generales que necesita un sprite u otro código. Si incluye gráficos de poses dinámicas, la herramienta los organiza para que puedan cargarse con la distribución de tiles que espera el sistema.&lt;br /&gt;
&lt;br /&gt;
Por cada pose guarda varios datos en tablas separadas. Todas mantienen el mismo orden: la entrada de una pose en una tabla corresponde a esa misma pose en las demás. En la tabla siguiente, &#039;&#039;&#039;N&#039;&#039;&#039; es la cantidad de poses dinámicas instaladas.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || 2 × N || 2 || La cantidad de datos que utiliza cada pose, en bytes. Se utiliza para comprobar si su carga cabe en el presupuesto del frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || N || 1 || Cuántos bloques de 16×16 hay que reservar en VRAM para la pose. No siempre coincide exactamente con los bytes que se copian, porque una pieza incompleta también puede necesitar un bloque de espacio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 × N || 3 || La dirección de los gráficos de cada pose en ROM. Incluye el banco, de modo que el código de carga pueda encontrar su origen completo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 × N || 2; dos valores por pose || Dos tamaños por pose, correspondientes a los dos tramos en que pueden dividirse sus gráficos. La rutina de carga utiliza esos tamaños para repartirlos correctamente en VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 × N || 2 || El desplazamiento en VRAM desde el comienzo del primer tramo hasta el comienzo del segundo. Permite colocar el segundo tramo donde corresponde, aunque el primero termine con una fila incompleta.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas describen todas las poses instaladas, no solo las que están en pantalla. Más adelante, la caché guarda por separado cuáles están cargadas y dónde quedaron.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si se solicita una pose que todavía no está en VRAM, el sistema consulta cuántos bytes necesita cargar, busca espacio para sus bloques y utiliza la dirección y los datos de sus tramos para preparar la carga.&lt;br /&gt;
&lt;br /&gt;
==== Tablas de paletas ====&lt;br /&gt;
&lt;br /&gt;
Las paletas declaradas en los DynamicInfo se reúnen en &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. Si &#039;&#039;&#039;P&#039;&#039;&#039; es la cantidad de entradas de las listas de paletas de los DynamicInfo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; || 2 × P || 2 || ID de cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; || 3 × P || 3 || Dirección de sus colores en ROM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
P cuenta las entradas de las listas, no solo las paletas distintas: una paleta compartida puede aparecer en más de un DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
Las dos listas siguen el orden de las paletas de los DynamicInfo. El define de offset de cada DynamicInfo indica dónde comienza su lista dentro de ellas. Al elegir una versión, el sistema suma ese índice al offset y obtiene tanto el ID como la dirección de los colores elegidos.&lt;br /&gt;
&lt;br /&gt;
El ID permite reconocer y compartir una paleta; la dirección permite cargarla. No son el número de paleta de pantalla: una misma paleta instalada puede terminar, por ejemplo, en la paleta 9 o en la C según la asignación.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y defines ====&lt;br /&gt;
&lt;br /&gt;
Los archivos declarados en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; se guardan en ROM. Su dirección y la cantidad de bytes que ocupan pueden consultarse mediante los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Por ejemplo, para &amp;lt;code&amp;gt;my_resource.bin&amp;lt;/code&amp;gt; se generan:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt;: dirección del recurso en ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt;: cantidad de bytes que ocupa.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt;: ID del recurso.&lt;br /&gt;
&lt;br /&gt;
El nombre se normaliza en PascalCase: se eliminan espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: datos y rutinas de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El DrawInfo describe cómo está formada una pose: qué tiles tiene, dónde se coloca cada uno, qué tamaño utiliza y cómo cambia al voltearse.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, Dynamic Xtreme genera rutinas de dibujo optimizadas según los parámetros que utilizan los tiles. Tiene en cuenta, por ejemplo, si necesitan desplazamientos X e Y, si comparten el mismo tamaño, si utilizan propiedades comunes y si requieren volteos.&lt;br /&gt;
&lt;br /&gt;
De esta forma, la rutina realiza el trabajo que necesita ese dibujo sin añadir el manejo de opciones que no utiliza. Varias poses pueden compartirla si necesitan el mismo tratamiento; eso no significa que compartan también sus gráficos o su ID.&lt;br /&gt;
&lt;br /&gt;
La relación entre una pose y su dibujo se guarda en estas tablas. &#039;&#039;&#039;D&#039;&#039;&#039; es la cantidad de poses de dibujo y &#039;&#039;&#039;R&#039;&#039;&#039; la cantidad de rutinas generadas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || 2 × D || 2 || Dónde comienzan los datos de la pose dentro de las tablas de su rutina de dibujo. Así se localizan sus tiles y desplazamientos sin recorrer las poses anteriores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || D || 1 || La cantidad de tiles de la pose menos uno. Una pose de cuatro tiles guarda 3; la rutina utiliza ese valor para recorrer sus piezas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || D || 1 || Qué rutina de dibujo utiliza cada pose. Las poses con características compatibles pueden apuntar al mismo ID de rutina.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || 3 × R || 3 por rutina || Las direcciones de las rutinas de dibujo. El ID de rutina permite encontrar aquí el código que debe ejecutarse.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada rutina tiene, además, las tablas que necesitan sus poses. Aquí &#039;&#039;&#039;T&#039;&#039;&#039; es la cantidad de entradas de cada tabla de la rutina:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos !! Bytes totales !! Bytes por valor !! Qué describen&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || T, si se genera || 1 || Los números de tile que forman la pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || T, si se genera || 1 || Las propiedades de cada pieza, como los volteos y su prioridad respecto a las capas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || T por tabla, si se genera || 1 || La posición de cada tile respecto al punto de origen de la pose.&lt;br /&gt;
|-&lt;br /&gt;
| Tablas de desplazamientos para los volteos || T por tabla, si se genera || 1 || Las posiciones que deben utilizarse al voltear la pose cuando necesita una distribución distinta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || T, si se genera || 1 || El tamaño de cada tile: 8×8 o 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
No todas estas tablas tienen que aparecer en todas las rutinas. Si un dato es igual para todas las piezas o puede obtenerse de un valor común, la herramienta puede generar una rutina que lo utilice directamente.&lt;br /&gt;
&lt;br /&gt;
La optimización se hace durante la instalación. Si todos los tiles tienen el mismo tamaño, por ejemplo, la rutina puede utilizar ese valor común sin leer un tamaño distinto para cada pieza.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: datos de los efectos ===&lt;br /&gt;
&lt;br /&gt;
Un archivo PaletteEffect contiene una lista de cambios de color. La instalación les asigna IDs y guarda sus datos en &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Como en las tablas de poses, los datos de cada efecto mantienen la misma posición en las distintas listas. Los IDs de efectos comienzan en 1; el ID 0 se utiliza para indicar que no hay efecto global. En la tabla, &#039;&#039;&#039;E&#039;&#039;&#039; es la cantidad de efectos instalados; el conjunto ocupa &#039;&#039;&#039;2 + 7 × E bytes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parte de la tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || 2 || 2 || La cantidad de efectos instalados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || E || 1 || El tipo de cada efecto, por ejemplo &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Indica qué cálculo debe realizarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || E por tabla; 3 × E entre las tres || 1 por tabla || Los valores de los canales que utiliza el efecto. En una transición, estos tres bytes guardan la dirección de la paleta de destino, no valores de canales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || E por tabla; 3 × E entre las tres || 1 por tabla || Cuánto se aplica el cambio en cada componente. Van de 0 a 127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Si el efecto es una transición hacia otra paleta, la herramienta también prepara esa paleta. Convierte sus colores al formato RGB o HSL que necesita la transición y los guarda en ROM. Durante el juego se puede utilizar ese destino sin tener que convertirlo de nuevo en cada llamada.&lt;br /&gt;
&lt;br /&gt;
Estas paletas de transición son distintas de las paletas normales que se cargan a CGRAM: contienen tres componentes por color y se utilizan para calcular el efecto.&lt;br /&gt;
&lt;br /&gt;
=== Cómo encuentra el código los recursos instalados ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; publica los IDs, direcciones, tamaños y offsets que necesitan los recursos. Por ejemplo, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifica una pose y &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifica el primer efecto de un archivo.&lt;br /&gt;
&lt;br /&gt;
Los nombres se normalizan en PascalCase: se eliminan separadores como espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra. &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, por ejemplo, pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También se genera &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, que guarda las direcciones de los bloques donde se insertaron los recursos. Cada dirección ocupa 3 bytes y se añade un valor final &amp;lt;code&amp;gt;$FFFFFF&amp;lt;/code&amp;gt; de otros 3 bytes. Para B bloques, ocupa &amp;lt;code&amp;gt;3 × (B + 1)&amp;lt;/code&amp;gt; bytes. La herramienta utiliza esa información para localizar los datos de una instalación anterior al reinstalar.&lt;br /&gt;
&lt;br /&gt;
Una reinstalación puede cambiar IDs y direcciones. Por eso hay que volver a insertar los sprites, bloques y códigos UberASM que utilizan los defines generados.&lt;br /&gt;
&lt;br /&gt;
== El trabajo de cada frame ==&lt;br /&gt;
&lt;br /&gt;
En la lógica principal se ejecutan el jugador, los sprites y los demás códigos del modo de juego. Los que utilizan Dynamic Xtreme solicitan las poses y paletas que necesitan, preparan los efectos locales y llaman a las rutinas de dibujo. Las cargas que se aceptan quedan anotadas para transferir sus datos durante NMI.&lt;br /&gt;
&lt;br /&gt;
Al terminar esa lógica, el código de game mode de Dynamic Xtreme realiza las tareas que correspondan a las opciones habilitadas: prepara las actualizaciones de VRAM de la optimización de Kevin, mantiene el estado de las paletas y calcula los efectos globales pendientes.&lt;br /&gt;
&lt;br /&gt;
Después, durante NMI, se ejecutan las transferencias preparadas: los gráficos se copian a VRAM y los colores a CGRAM. También se reinicia el contador de datos y se actualizan los relojes del sistema para el siguiente ciclo de trabajo.&lt;br /&gt;
&lt;br /&gt;
El orden que seguiremos para explicarlo es, por tanto, &#039;&#039;&#039;lógica principal → tareas al terminar el game mode → transferencias durante NMI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Lógica principal ===&lt;br /&gt;
&lt;br /&gt;
Cada recurso decide qué necesita. Un sprite puede cambiar de pose, una animación puede pedir nuevos gráficos y un código UberASM puede cargar una paleta o seleccionar un efecto.&lt;br /&gt;
&lt;br /&gt;
Si la pose solicitada ya está cargada, Dynamic Xtreme actualiza su tiempo de último uso para protegerla del reemplazo y no vuelve a cargar sus gráficos. Si no está cargada, comprueba el presupuesto de datos del frame y busca espacio disponible en VRAM antes de preparar su carga.&lt;br /&gt;
&lt;br /&gt;
El dibujo también se prepara en esta parte: las rutinas escriben en los buffers OAM la posición, los tiles y las propiedades de las piezas que se mostrarán.&lt;br /&gt;
&lt;br /&gt;
Una solicitud puede rechazarse, por ejemplo si no queda presupuesto para sus datos. El recurso que la pidió debe comprobar el resultado y decidir si conserva lo anterior o vuelve a intentarlo después. Una carga rechazada no queda guardada automáticamente para otro frame.&lt;br /&gt;
&lt;br /&gt;
=== Tareas de game mode ===&lt;br /&gt;
&lt;br /&gt;
En esta parte se realizan las siguientes tareas, según las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antes de ejecutar la lógica del juego:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitado &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;, se ejecuta la rutina del control aquí en lugar de hacerlo en NMI.&lt;br /&gt;
# Se comprueba si Dynamic Xtreme debe funcionar en el game mode actual. Si no debe hacerlo, se reinician sus variables. Esto ocurre cada frame que se permanezca en un modo no permitido.&lt;br /&gt;
&lt;br /&gt;
Después se ejecuta la lógica normal del juego, incluidos los sprites y los códigos que solicitan cargas o cambios de paleta.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cuando termina esa lógica:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitada la optimización de VRAM de Kevin, se ajustan los destinos de las actualizaciones de Lunar Magic antes de que se transfieran.&lt;br /&gt;
# Se ponen en 0 los indicadores de actualización de las paletas y se resta 1 a sus temporizadores de protección si todavía son mayores que 0. Esta parte se omite durante la pausa y en los modos no permitidos.&lt;br /&gt;
# Se aplican los efectos globales a las paletas que necesitan actualizarse y se preparan las transferencias de sus colores. Esta parte también se omite si la comprobación anterior impide continuar.&lt;br /&gt;
&lt;br /&gt;
Las copias a VRAM y CGRAM se realizan después, durante NMI. Aquí se deja preparado lo que se va a copiar.&lt;br /&gt;
&lt;br /&gt;
=== Transferencias durante NMI ===&lt;br /&gt;
&lt;br /&gt;
NMI es una interrupción que SNES puede generar al comenzar VBlank, después de dibujar la parte visible de la pantalla. El juego aprovecha ese intervalo para actualizar gráficos, colores y otros datos de video.&lt;br /&gt;
&lt;br /&gt;
En los modos permitidos, la rutina de Dynamic Xtreme reinicia &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; y actualiza sus relojes. Después ejecuta las transferencias de gráficos pendientes y luego las de paletas. Si corresponde, también actualiza el color 0,0 preparado por el sistema de efectos.&lt;br /&gt;
&lt;br /&gt;
Para realizar las copias se utiliza DMA. NMI lee cada carga de las listas, configura desde dónde se copiarán los datos, cuántos bytes se copiarán y dónde se colocarán, y ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
El tiempo de VBlank es limitado y SMW también lo necesita para sus actualizaciones de pantalla. Para limitar la cantidad de datos enviados en un frame y evitar flickering, Dynamic Xtreme utiliza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, que cuenta los bytes de las cargas solicitadas, y &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, que establece el límite permitido. Antes de aceptar una carga normal, se comprueba que sus bytes no hagan superar ese límite.&lt;br /&gt;
&lt;br /&gt;
==== Las listas de transferencias ====&lt;br /&gt;
&lt;br /&gt;
Cada transferencia guarda el origen de los datos, su banco, la cantidad de bytes y el destino en VRAM o CGRAM.&lt;br /&gt;
&lt;br /&gt;
Al realizar las copias, NMI recorre las listas desde la última entrada hacia la primera y después las vacía. Esto no borra los gráficos o colores cargados: permanecen en su destino hasta que otro código los cambie.&lt;br /&gt;
&lt;br /&gt;
La lista de VRAM utiliza 0 cuando no tiene entradas. La de CGRAM utiliza &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, porque guarda el índice de la última entrada en lugar de guardar directamente su cantidad.&lt;br /&gt;
&lt;br /&gt;
Si dos códigos escriben sobre el mismo destino, deben coordinar sus cargas. El orden de las solicitudes no debe utilizarse como sustituto de decidir qué recurso puede ocupar cada espacio.&lt;br /&gt;
&lt;br /&gt;
Normalmente, el recurso se lee desde ROM. Si el recurso se encuentra en un buffer en RAM, el usuario debe conservar su contenido hasta que NMI realice la transferencia. Por ejemplo, si prepara una paleta en RAM, no debe modificar ni reutilizar ese buffer antes de que se copie. La lista guarda su dirección, no una copia de sus datos; Dynamic Xtreme no protege el buffer contra cambios realizados por otros códigos.&lt;br /&gt;
&lt;br /&gt;
==== Presupuesto de datos ====&lt;br /&gt;
&lt;br /&gt;
Las macros de transferencia, como &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt;, comprueban cuántos bytes se han solicitado mediante &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;. Si al añadir la nueva carga se supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, la rechazan. Si la aceptan, suman sus bytes al contador.&lt;br /&gt;
&lt;br /&gt;
El límite predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Su objetivo es evitar flickering por enviar demasiados datos en un mismo frame. Es un límite de cantidad de datos, no una medida exacta del tiempo que tarda cada transferencia.&lt;br /&gt;
&lt;br /&gt;
Estas macros tienen variantes como &amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ForcedTransferToCGRAM()&amp;lt;/code&amp;gt;, que aceptan la carga sin comprobar si supera el límite. Sus bytes también se suman a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, por lo que reducen lo que queda disponible para las siguientes cargas normales. Se utilizan para cargas prioritarias, como las del jugador; usarlas no evita el flickering si se solicita una cantidad excesiva de datos.&lt;br /&gt;
&lt;br /&gt;
==== Los dos relojes ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_Timer: protección de las solicitudes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza cuando se ejecuta la parte de NMI de Dynamic Xtreme. Además de medir cuánto lleva una pose sin utilizarse, sirve para evitar que un recurso repita sus solicitudes antes de que se procesen las anteriores.&lt;br /&gt;
&lt;br /&gt;
No siempre hay un ciclo de lógica por cada ejecución completa de NMI. Durante slowdown, SMW puede ejecutar una versión reducida de NMI, y puede haber dos ciclos de lógica sin que entre ellos se hayan procesado las listas de transferencias de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Sin una protección, un recurso podría añadir otra vez sus cargas a esas listas. Las solicitudes repetidas ocuparían más espacio y podrían provocar flickering.&lt;br /&gt;
&lt;br /&gt;
Para evitarlo, las rutinas con esta protección comparan &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; con un valor guardado por el recurso, normalmente llamado &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt;. Si coinciden, el recurso ya hizo su intento con ese valor del reloj y no debe añadir de nuevo las cargas. Si son distintos, guarda el valor actual y puede realizar la nueva solicitud.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; continúa avanzando durante la pausa cuando se ejecuta esa parte de NMI.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_SyncTimer: animaciones sincronizadas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
La función principal de &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; es dar a los sprites un reloj común para sus animaciones. Por ejemplo, varios sprites que utilizan las mismas poses pueden calcular con este reloj qué pose les corresponde cada cuatro frames.&lt;br /&gt;
&lt;br /&gt;
Así todos cambian al mismo tiempo y solicitan la misma pose. La primera solicitud puede necesitar cargarla; las demás la reutilizan sin programar otra carga de sus gráficos. Esto ahorra transferencias DMA y datos enviados por frame.&lt;br /&gt;
&lt;br /&gt;
Si cada sprite llevara un reloj independiente, podrían terminar usando poses distintas de la misma animación al mismo tiempo y necesitar más cargas y espacio de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; se detiene durante la pausa y cuando se congela la acción, para que las animaciones sincronizadas también se detengan.&lt;br /&gt;
&lt;br /&gt;
== Carga de gráficos: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; guarda en RAM una lista de solicitudes de carga. Durante NMI se recorren esas solicitudes y se copian sus datos a VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Variables de la lista ===&lt;br /&gt;
&lt;br /&gt;
En esta tabla, &#039;&#039;&#039;V&#039;&#039;&#039; es el valor de &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt;: 64 por defecto. Las cuatro tablas de solicitudes reservan V bytes cada una; con entradas de 2 bytes, ese valor deja espacio para 32 solicitudes. Junto con el contador, reservan &amp;lt;code&amp;gt;1 + 4 × V&amp;lt;/code&amp;gt; bytes: 257 por defecto.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de solicitudes pendientes. El valor 0 indica que la lista está vacía.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Dirección de origen de cada solicitud, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 reservados; banco de 1 byte || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Cantidad de bytes que se copiarán.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || V; 64 por defecto || 2 || Dirección de destino en VRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las tablas mantienen el mismo orden: la primera entrada de cada tabla pertenece a la primera solicitud, la segunda a la segunda, etc. Cada entrada de estas tablas ocupa 2 bytes, por lo que se avanza con desplazamientos de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt;, etc.&lt;br /&gt;
&lt;br /&gt;
Estos nombres representan direcciones de RAM calculadas en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus direcciones pueden cambiar según la configuración y las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
=== Añadir una solicitud ===&lt;br /&gt;
&lt;br /&gt;
La macro &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; realiza los siguientes pasos:&lt;br /&gt;
&lt;br /&gt;
# Calcula cuántos bytes habría en total al añadir la nueva carga a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Compara el resultado con &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;. Si lo supera, devuelve el carry desactivado y no añade la solicitud.&lt;br /&gt;
# Utiliza &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para encontrar la siguiente entrada y aumenta ese contador en 1.&lt;br /&gt;
# Guarda el origen, banco, cantidad de bytes y destino en las tablas.&lt;br /&gt;
# Actualiza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; con los bytes de la carga y devuelve el carry activado.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; guarda los mismos datos, pero no comprueba el límite de bytes. Las variantes &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; facilitan obtener el origen desde una dirección completa o desde los defines de un recurso.&lt;br /&gt;
&lt;br /&gt;
Añadir una solicitud no copia los gráficos inmediatamente: deja la información preparada para NMI.&lt;br /&gt;
&lt;br /&gt;
=== Ejecutar las solicitudes durante NMI ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Lee &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;. Si es 0, termina porque no hay solicitudes.&lt;br /&gt;
# Calcula el desplazamiento de la última entrada: &amp;lt;code&amp;gt;(Length - 1) × 2&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Lee su origen, banco y cantidad de bytes, y los coloca en los registros de DMA.&lt;br /&gt;
# Escribe el destino de VRAM en &amp;lt;code&amp;gt;$2116-$2117&amp;lt;/code&amp;gt; e inicia la transferencia mediante &amp;lt;code&amp;gt;$420B&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Retrocede 2 bytes para procesar la solicitud anterior. Repite hasta completar la primera.&lt;br /&gt;
# Escribe 0 en &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para indicar que la lista está vacía.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;La lista se ejecuta del final al inicio.&#039;&#039;&#039; No hace falta borrar todos sus datos al terminar: al quedar su largo en 0, la próxima solicitud volverá a utilizar la primera entrada.&lt;br /&gt;
&lt;br /&gt;
=== Animaciones con un destino fijo ===&lt;br /&gt;
&lt;br /&gt;
El código de una animación debe:&lt;br /&gt;
&lt;br /&gt;
# Elegir la imagen que corresponde al paso actual.&lt;br /&gt;
# Calcular su dirección de origen.&lt;br /&gt;
# Solicitar la copia al destino de VRAM de la animación.&lt;br /&gt;
# Comprobar el carry. Si se rechaza la carga, conservar la imagen anterior y volver a intentarlo.&lt;br /&gt;
&lt;br /&gt;
El destino puede ser siempre el mismo. Lo que cambia es la imagen que se copia allí; la lista de transferencias no decide cuándo debe avanzar la animación.&lt;br /&gt;
&lt;br /&gt;
Puedes ver un código completo en [[es/Dynamic_Xtreme_UberASM_guide#Crear_animaciones_de_gráficos|Crear animaciones de gráficos de la guía de UberASM]].&lt;br /&gt;
&lt;br /&gt;
=== Carga de una pose dinámica ===&lt;br /&gt;
&lt;br /&gt;
La carga de una pose utiliza la caché para no repetir transferencias de gráficos que ya están disponibles:&lt;br /&gt;
&lt;br /&gt;
# Busca el ID en la tabla hash.&lt;br /&gt;
# Si ya está registrado, actualiza su tiempo de uso y no añade otra carga.&lt;br /&gt;
# Si no está, comprueba la cantidad de bytes y busca un espacio adecuado en el mapa de VRAM.&lt;br /&gt;
# Elige qué poses pueden reemplazarse, teniendo en cuenta su tiempo sin uso y el espacio que necesita la nueva.&lt;br /&gt;
# Actualiza las tablas de la caché y el mapa.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; divide los datos de la pose en las transferencias necesarias.&lt;br /&gt;
# NMI ejecuta esas transferencias.&lt;br /&gt;
&lt;br /&gt;
Cada paso se desarrolla en [[#Sprites_dinámicos:_DynamicPoses|Sprites dinámicos: DynamicPoses]], incluyendo la búsqueda por hash, el mapa, la política de reemplazo y la división de la carga en filas.&lt;br /&gt;
&lt;br /&gt;
== Carga y asignación de paletas: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
El sistema distingue dos valores:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID de paleta:&#039;&#039;&#039; identifica los colores guardados en ROM.&lt;br /&gt;
* &#039;&#039;&#039;Destino de pantalla:&#039;&#039;&#039; indica qué paleta de CGRAM utilizará esos colores.&lt;br /&gt;
&lt;br /&gt;
La asignación automática permite compartir colores entre sprites sin exigir un destino fijo para cada uno.&lt;br /&gt;
&lt;br /&gt;
=== Lista de cargas a CGRAM ===&lt;br /&gt;
&lt;br /&gt;
En esta tabla, &#039;&#039;&#039;C&#039;&#039;&#039; es &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt;: 64 por defecto. El conjunto reserva &amp;lt;code&amp;gt;1 + 7 × C&amp;lt;/code&amp;gt; bytes, es decir, 449 con ese valor. Aunque &amp;lt;code&amp;gt;SourceBNK&amp;lt;/code&amp;gt; reserva 2 × C bytes, el código utiliza un byte de banco por solicitud.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || 1 || 1 || Índice de la última solicitud pendiente. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; indica una lista vacía; 0 indica que hay una solicitud.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || 2 × C; 128 por defecto || 2 || Dirección de origen, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || 2 × C; 128 reservados por defecto || 1 utilizado por solicitud || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || 2 × C; 128 por defecto || 2 || Cantidad de bytes que se copiarán. Cada color ocupa 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || C; 64 por defecto || 1 || Primer color de destino en CGRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Durante NMI, &amp;lt;code&amp;gt;CGRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Comienza por la última solicitud pendiente.&lt;br /&gt;
# Configura DMA con el origen y la cantidad de bytes de esa solicitud.&lt;br /&gt;
# Selecciona el primer color mediante &amp;lt;code&amp;gt;$2121&amp;lt;/code&amp;gt; y realiza la copia.&lt;br /&gt;
# Continúa con las solicitudes anteriores.&lt;br /&gt;
# Al terminar, escribe &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; también actualizan las copias de colores y el estado de efectos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Sin efecto global:&#039;&#039;&#039; solicitan la carga y actualizan los buffers de SMW. Así el juego no vuelve a utilizar colores anteriores durante la animación de victoria del goal.&lt;br /&gt;
* &#039;&#039;&#039;Con efecto global:&#039;&#039;&#039; guardan los colores originales y preparan el estado necesario para aplicarles el efecto antes de enviarlos a CGRAM.&lt;br /&gt;
&lt;br /&gt;
=== Asignación automática ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 32 || 2 || Guarda el ID asignado a cada destino. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre y &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; una reservada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 16 || 1 || Protege cada destino del reemplazo automático mientras está en uso.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta de sprites || Indica qué paletas de sprites están asignadas con efecto global habilitado. Esta condición también se compara al compartir una asignación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue este orden:&lt;br /&gt;
&lt;br /&gt;
# Reutilizar una asignación con el mismo ID y una condición de efecto compatible.&lt;br /&gt;
# Si no existe, utilizar una entrada libre.&lt;br /&gt;
# Si no hay entradas libres, reemplazar una que no esté reservada y cuyo temporizador sea 0.&lt;br /&gt;
# Si no encuentra ninguna, indicar que la asignación falló.&lt;br /&gt;
&lt;br /&gt;
Mientras el recurso utiliza la paleta, mantiene su temporizador en 2. Llegar a 0 no borra los colores: la asignación puede reutilizarse si otro recurso todavía no la reemplazó.&lt;br /&gt;
&lt;br /&gt;
=== Asignación manual y versión ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Manual con carga:&#039;&#039;&#039; el código elige el destino y solicita sus colores.&lt;br /&gt;
* &#039;&#039;&#039;Manual sin carga:&#039;&#039;&#039; el código elige el destino y utiliza los colores que ya estaban preparados.&lt;br /&gt;
* &#039;&#039;&#039;Versión:&#039;&#039;&#039; selecciona una entrada de la lista de paletas del DynamicInfo. La última versión procesada permite comprobar si esa selección cambió.&lt;br /&gt;
&lt;br /&gt;
Dos recursos que elijan el mismo destino con colores distintos deben coordinarse. Mantener la protección de una paleta no significa volver a cargar sus colores.&lt;br /&gt;
&lt;br /&gt;
== Dibujo de poses: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
El dibujo prepara las piezas de una pose en OAM: qué tiles se muestran, dónde se colocan y qué propiedades utilizan. Los datos gráficos deben estar en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Pasos del dibujo ===&lt;br /&gt;
&lt;br /&gt;
# Busca la rutina y los datos de la pose mediante &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Obtiene la cantidad de piezas desde &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Calcula la posición de cada tile usando la posición del sprite, sus desplazamientos y los volteos que correspondan.&lt;br /&gt;
# Comprueba si la pieza puede verse y si queda espacio de OAM.&lt;br /&gt;
# Escribe su posición, número de tile, propiedades y tamaño en los buffers OAM.&lt;br /&gt;
&lt;br /&gt;
El número de tile depende del dibujo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Cómo se obtiene el tile&lt;br /&gt;
|-&lt;br /&gt;
| Pose dinámica || Se ajusta al lugar de VRAM donde quedaron cargados sus gráficos.&lt;br /&gt;
|-&lt;br /&gt;
| Pose estática || Se utiliza su número de tile fijo.&lt;br /&gt;
|-&lt;br /&gt;
| Pose que utiliza un tile común || El código debe preparar &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; antes de llamar al dibujo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Prioridad y espacio disponible ===&lt;br /&gt;
&lt;br /&gt;
* En &#039;&#039;&#039;LoROM&#039;&#039;&#039;, el sistema lleva su propio control de entradas OAM disponibles.&lt;br /&gt;
* En &#039;&#039;&#039;SA-1&#039;&#039;&#039;, utiliza la integración con MaxTile.&lt;br /&gt;
* La &#039;&#039;&#039;prioridad de dibujo&#039;&#039;&#039; organiza las piezas de sprites. No es la misma propiedad que determina si un tile queda delante o detrás de las capas.&lt;br /&gt;
* Los &#039;&#039;&#039;límites por línea de pantalla&#039;&#039;&#039; de SNES siguen existiendo. Tener una pose cargada no garantiza que puedan verse todas sus piezas.&lt;br /&gt;
&lt;br /&gt;
== Jugador y Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
El jugador original tiene rutinas propias para elegir y cargar las piezas de sus poses. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; permite integrar ese trabajo con las cargas de Dynamic Xtreme y cambiar el origen de sus gráficos y paletas.&lt;br /&gt;
&lt;br /&gt;
Con el formato original, el juego sigue eligiendo las piezas de la pose. La rutina obtiene sus direcciones desde el origen configurado y compara esas direcciones con las anteriores para cargar las que hayan cambiado.&lt;br /&gt;
&lt;br /&gt;
Estas cargas utilizan transferencias forzadas y sus bytes también cuentan para las solicitudes normales posteriores. Así conservan su prioridad sin quedar fuera de la contabilidad del sistema.&lt;br /&gt;
&lt;br /&gt;
La paleta del jugador tiene un tratamiento especial: combina colores y selecciones del propio juego con el origen personalizado. No funciona simplemente como sustituir una paleta completa de un sprite cualquiera.&lt;br /&gt;
&lt;br /&gt;
El soporte para jugadores personalizados permite que otros sistemas administren de otra forma sus poses y dibujo. No convierte automáticamente cualquier spritesheet al formato del jugador original.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi también carga sus gráficos por piezas. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; permite cambiar su origen manteniendo la organización que esperan sus rutinas.&lt;br /&gt;
&lt;br /&gt;
El código calcula qué partes necesita y prepara sus cargas a los destinos correspondientes de VRAM. Como las del jugador, estas cargas tienen un tratamiento prioritario.&lt;br /&gt;
&lt;br /&gt;
Esta opción necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad. No permite evitar un conflicto del sistema del jugador habilitando únicamente las funciones de Yoshi.&lt;br /&gt;
&lt;br /&gt;
== Memoria y optimizaciones ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW mantiene en RAM gráficos originales del jugador, Yoshi y ciertas animaciones. En ROMs sin SA-1, esta opción adapta las cargas para leer esos datos desde ROM.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aprovecha la RAM recuperada para sus variables internas. No es un espacio que quede libre para que cualquier otro código escriba encima.&lt;br /&gt;
&lt;br /&gt;
SA-1 utiliza otras direcciones y desactiva esta opción. Los rangos están en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
Esta opción mueve el procesamiento del control desde NMI a la parte de game mode. El objetivo es dejar más tiempo para las actualizaciones de pantalla, no añadir un frame de retraso ni cambiar los botones que recibe el juego.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
El color fijo se utiliza en las mezclas de color de la consola. Para actualizarlo, el juego prepara sus componentes y los envía al registro correspondiente.&lt;br /&gt;
&lt;br /&gt;
La optimización reemplaza esa preparación por una secuencia más corta. El color sigue enviándose a la consola, pero necesita menos trabajo durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic utiliza listas llamadas stripe images para actualizar partes de los mapas de tiles. Esas listas incluyen tanto los datos como la información sobre sus destinos.&lt;br /&gt;
&lt;br /&gt;
La versión integrada de la optimización de Kevin prepara fuera de NMI parte del ajuste de esos destinos. Así deja menos trabajo de preparación para el momento de la transferencia.&lt;br /&gt;
&lt;br /&gt;
Esta opción sustituye el uso del parche original por separado. Además, no debe desinstalarse después de instalarla; hay que tenerlo en cuenta antes de activarla.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
La barra de estado original actualiza zonas concretas de VRAM. Esta opción prepara sus transferencias de forma más directa, reduciendo la configuración de DMA que necesita hacer durante NMI.&lt;br /&gt;
&lt;br /&gt;
No añade una barra nueva. Modifica la actualización de la original y, por eso, entra en conflicto con recursos que la reemplazan, modifican o eliminan.&lt;br /&gt;
&lt;br /&gt;
== Sprites dinámicos: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
El sistema funciona como una &#039;&#039;&#039;caché de poses en VRAM&#039;&#039;&#039;. No reserva una copia de los gráficos para cada sprite: guarda la pose y permite que la reutilicen todos los recursos que la necesiten.&lt;br /&gt;
&lt;br /&gt;
* Una pose se carga una sola vez mientras permanezca en la caché.&lt;br /&gt;
* Las siguientes solicitudes actualizan su tiempo de último uso, sin añadir otra carga de sus gráficos.&lt;br /&gt;
* La pose no se borra cuando un recurso deja de utilizarla. Permanece allí hasta que se necesite su espacio y se elija reemplazarla.&lt;br /&gt;
* Si fue reemplazada y vuelve a solicitarse, tendrá que cargarse otra vez.&lt;br /&gt;
&lt;br /&gt;
La elección no depende de cuánto tiempo lleva la pose desde que se cargó, sino de &#039;&#039;&#039;cuánto tiempo lleva sin utilizarse&#039;&#039;&#039; y de si su espacio sirve para la pose nueva.&lt;br /&gt;
&lt;br /&gt;
=== Tres valores distintos ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Qué identifica&lt;br /&gt;
|-&lt;br /&gt;
| ID de pose || La pose instalada. Tiene 16 bits y permite consultar sus datos en ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Índice de la tabla hash || La entrada de RAM donde se registró la pose. Va de 0 a 127.&lt;br /&gt;
|-&lt;br /&gt;
| Bloque de VRAM || La posición donde comienzan sus gráficos dentro del espacio de sprites. Va de 0 a 127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
El índice de la tabla hash y el bloque de VRAM no tienen por qué coincidir. Una entrada de la tabla puede registrar una pose que empieza en cualquier bloque permitido.&lt;br /&gt;
&lt;br /&gt;
=== Tablas de las poses registradas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Bytes totales !! Bytes por valor !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de poses registradas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 || 1 || Cantidad de poses registradas para cada hash.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 256 || 2 || ID completo de la pose de cada entrada. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Bloque de VRAM donde comienza cada pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 256 || 2 || Valor de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; de su último uso.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas ocupan &#039;&#039;&#039;769 bytes&#039;&#039;&#039; en RAM. Guardan las poses registradas durante el juego; las tablas generadas desde el DynamicInfo describen, en cambio, todas las poses instaladas.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se busca una pose ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;DynamicPoseHashmap_FindPose&amp;lt;/code&amp;gt; utiliza una tabla hash de 128 entradas. El hash permite elegir dónde empezar a buscar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hash = ID de pose AND $007F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dos IDs diferentes pueden tener el mismo hash. Por ejemplo, &amp;lt;code&amp;gt;$0005&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0085&amp;lt;/code&amp;gt; producen &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;. Por eso el hash no basta para confirmar que la pose está cargada: también se compara el ID completo.&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue estos pasos:&lt;br /&gt;
&lt;br /&gt;
# Guarda el ID solicitado y calcula su hash.&lt;br /&gt;
# Si &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; es 0, no hay poses registradas y la búsqueda termina.&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize[hash]&amp;lt;/code&amp;gt;. Si es 0, ninguna pose registrada tiene ese hash y también termina.&lt;br /&gt;
# Comienza por la entrada cuyo índice coincide con el hash.&lt;br /&gt;
# Lee el ID de esa entrada. Si coincide con el solicitado, encontró la pose.&lt;br /&gt;
# Si no coincide, continúa con la siguiente entrada de la secuencia de búsqueda.&lt;br /&gt;
&lt;br /&gt;
La secuencia avanza &#039;&#039;&#039;15 entradas por intento&#039;&#039;&#039; y vuelve al comienzo al superar 127:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
siguiente índice = (índice actual + 15) AND $7F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Con 128 entradas, ese paso permite visitar todas las posiciones antes de repetir una. Para el hash &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;, el comienzo de la secuencia es:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$05 → $14 → $23 → $32 → $41 → ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El sistema no necesita recorrer siempre las 128 entradas. &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; indica cuántas poses de ese hash hay que comprobar. Al encontrar una pose distinta con el mismo hash, descuenta una del contador de búsqueda; si ya comprobó todas sin encontrar el ID solicitado, termina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Una entrada libre no termina la búsqueda.&#039;&#039;&#039; Puede haber quedado vacía al reemplazar una pose y existir otra del mismo hash más adelante. Las entradas de otros hashes tampoco descuentan el contador de poses que faltan por comprobar.&lt;br /&gt;
&lt;br /&gt;
==== Cuando encuentra la pose ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Obtiene el índice de la entrada encontrada.&lt;br /&gt;
# Escribe el valor actual de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; para esa entrada.&lt;br /&gt;
# Devuelve el éxito de la solicitud, sin volver a programar la carga de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
Así todos los recursos que solicitan ese ID utilizan la misma pose y la mantienen protegida. No importa si el recurso es un sprite normal, cluster, extended u otro código que utiliza el sistema.&lt;br /&gt;
&lt;br /&gt;
Esto también evita duplicar una carga dentro del mismo ciclo: cuando la primera solicitud se acepta, la pose ya queda registrada aunque la transferencia física se vaya a realizar durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== Cuando la pose no está registrada ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt; continúa con la preparación de una carga nueva:&lt;br /&gt;
&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; y calcula &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend + PoseSize&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, termina con fallo, sin cambiar las poses existentes.&lt;br /&gt;
# Consulta &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; para saber cuántos bloques necesita.&lt;br /&gt;
# Llama a &amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; para buscar un espacio adecuado.&lt;br /&gt;
# Si no existe un espacio utilizable, termina con fallo.&lt;br /&gt;
# Retira del mapa y de la tabla hash las poses que ocupen el espacio elegido.&lt;br /&gt;
# Busca una entrada libre de la tabla hash y registra la pose nueva.&lt;br /&gt;
# Actualiza el mapa de VRAM y el contador de datos del frame.&lt;br /&gt;
# Llama a &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; para añadir las transferencias.&lt;br /&gt;
&lt;br /&gt;
El presupuesto se comprueba antes de reemplazar poses. Si la nueva carga no cabe en el frame, no se libera espacio para una solicitud que no se puede atender.&lt;br /&gt;
&lt;br /&gt;
==== Añadir y quitar entradas de la tabla hash ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_FindFreeSpace&amp;lt;/code&amp;gt; busca una entrada cuyo ID sea &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt;, siguiendo la misma secuencia de pasos de 15.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; guarda el ID y su tiempo de uso, aumenta &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; y aumenta el contador de su hash.&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoseHashmap_Remove&amp;lt;/code&amp;gt; escribe &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; en el ID retirado y reduce ambos contadores.&lt;br /&gt;
&lt;br /&gt;
Retirar una entrada no borra por sí solo los píxeles de VRAM. Indica que esa pose dejó de estar disponible en la caché; las nuevas transferencias sobrescribirán el espacio elegido.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se representa el mapa de VRAM ===&lt;br /&gt;
&lt;br /&gt;
El mapa tiene &#039;&#039;&#039;128 bloques&#039;&#039;&#039; de gráficos de 16×16. En 4bpp, un bloque completo equivale a 128 bytes de gráficos. Las poses incompletas pueden copiar menos datos, pero necesitan reservar los bloques que ocupan.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 || 1 || Bloque donde comienza la región. El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica que está reservada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt;, también llamada &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 || 1 || Si el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; está activo, los otros bits guardan el tamaño de la región libre menos uno. Si está desactivado, guardan el índice de la pose en la tabla hash.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Son &#039;&#039;&#039;256 bytes&#039;&#039;&#039; adicionales. Junto con las tablas de poses, el administrador utiliza &#039;&#039;&#039;1025 bytes&#039;&#039;&#039; de RAM, sin contar las listas de DMA ni las scratch de trabajo.&lt;br /&gt;
&lt;br /&gt;
El mapa guarda la información en los extremos de cada región: su primer y su último bloque. No necesita mantener un registro independiente de la pose en cada bloque intermedio.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, una región libre de 6 bloques, desde &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; hasta &amp;lt;code&amp;gt;$25&amp;lt;/code&amp;gt;, guarda en ambos extremos:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Offset = $20&amp;lt;/code&amp;gt;: comienzo de la región.&lt;br /&gt;
* &amp;lt;code&amp;gt;Size = $85&amp;lt;/code&amp;gt;: bit de región libre &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; más el tamaño menos uno, &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Si la región está ocupada, el tamaño se obtiene consultando el ID de su entrada hash y después &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Las configuraciones de &amp;lt;code&amp;gt;DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; preparan las regiones disponibles y reservadas de SP1-SP4. Una región reservada no puede elegirse para una pose nueva.&lt;br /&gt;
&lt;br /&gt;
=== Recorrido y búsqueda de espacio ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMap_GetBestSlot&amp;lt;/code&amp;gt; comienza en el bloque &amp;lt;code&amp;gt;$7F&amp;lt;/code&amp;gt; y recorre las regiones hacia atrás:&lt;br /&gt;
&lt;br /&gt;
# Lee el comienzo de la región desde &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Comprueba si está reservada.&lt;br /&gt;
# Obtiene su tamaño y su puntuación de tiempo sin uso.&lt;br /&gt;
# Comprueba si sirve para la pose solicitada o si debe considerar también una región contigua.&lt;br /&gt;
# Para pasar a la región anterior, utiliza &amp;lt;code&amp;gt;comienzo de la región - 1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El registro del último bloque permite saltar regiones completas. No se recorren uno por uno todos los bloques que ocupa una pose.&lt;br /&gt;
&lt;br /&gt;
Durante la búsqueda se conservan los datos del espacio que se está evaluando y del mejor encontrado:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos de trabajo !! Bytes totales !! Bytes por valor !! Para qué se usan&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapCurrentSpace&amp;lt;/code&amp;gt; || 3 || 1 por campo || Comienzo, puntuación y cantidad de bloques del candidato actual.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapBestSpace&amp;lt;/code&amp;gt; || 3 || 1 por campo || Los mismos campos para el mejor candidato encontrado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VRAMMapTMP_Size&amp;lt;/code&amp;gt; || 1 || 1 || Cantidad de bloques que necesita la pose nueva.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos nombres son datos temporales en scratch, no reservas adicionales de RAM persistente.&lt;br /&gt;
&lt;br /&gt;
=== Política de reemplazo: tiempo sin uso y espacio suficiente ===&lt;br /&gt;
&lt;br /&gt;
El sistema no elige simplemente la pose que se cargó primero. Utiliza el tiempo transcurrido desde su &#039;&#039;&#039;último uso&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tiempo sin uso = DX_Timer - TimeLastUse de la pose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VRAMMapSlot_GetSizeAndScore&amp;lt;/code&amp;gt; obtiene el tamaño y una puntuación para cada región:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Puntuación y tratamiento&lt;br /&gt;
|-&lt;br /&gt;
| Región libre || &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Se favorece frente a regiones ocupadas.&lt;br /&gt;
|-&lt;br /&gt;
| Región ocupada || Tiempo sin uso, limitado a &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Tiempo sin uso de 0 o 1 || No se puede reemplazar: la pose sigue protegida.&lt;br /&gt;
|-&lt;br /&gt;
| Región reservada || Se descarta, independientemente del tiempo sin uso.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La protección exige &#039;&#039;&#039;al menos dos avances de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; sin utilizar la pose&#039;&#039;&#039;. Cada recurso que vuelve a solicitarla actualiza su tiempo de uso y vuelve a protegerla.&lt;br /&gt;
&lt;br /&gt;
==== Por qué no siempre se reemplaza la pose con más tiempo sin uso ====&lt;br /&gt;
&lt;br /&gt;
La pose nueva necesita espacio suficiente y contiguo. Un espacio pequeño no sirve por sí solo, aunque lleve mucho tiempo sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para una pose nueva de 4 bloques:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Espacio candidato !! Tiempo sin uso !! ¿Sirve?&lt;br /&gt;
|-&lt;br /&gt;
| Pose A: 2 bloques, sin espacio contiguo utilizable || 20 || No: solo deja 2 bloques.&lt;br /&gt;
|-&lt;br /&gt;
| Pose B: 4 bloques || 8 || Sí: puede alojar la pose nueva.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
En este caso se puede reemplazar B y conservar A. A lleva más tiempo sin uso, pero su espacio no permite atender la solicitud.&lt;br /&gt;
&lt;br /&gt;
Si dos o más regiones contiguas pueden reemplazarse, el sistema puede considerarlas juntas. Para esa combinación:&lt;br /&gt;
&lt;br /&gt;
* Suma sus cantidades de bloques.&lt;br /&gt;
* Utiliza la &#039;&#039;&#039;menor puntuación&#039;&#039;&#039; de las regiones combinadas, es decir, el menor tiempo sin uso.&lt;br /&gt;
* Si una está reservada o protegida, no puede utilizarla para completar el espacio.&lt;br /&gt;
&lt;br /&gt;
Así una pose usada recientemente no puede quedar sobrescrita por combinarla con otra que lleva mucho tiempo sin uso.&lt;br /&gt;
&lt;br /&gt;
==== Elegir entre candidatos válidos ====&lt;br /&gt;
&lt;br /&gt;
# El candidato debe tener al menos la cantidad de bloques solicitada.&lt;br /&gt;
# Se prefiere la puntuación más alta: espacio libre o mayor tiempo sin uso.&lt;br /&gt;
# Si las puntuaciones son iguales, se prefiere el candidato con menos bloques, siempre que la pose quepa.&lt;br /&gt;
# Si puntuación y tamaño también coinciden, se conserva el candidato que ya se había elegido.&lt;br /&gt;
&lt;br /&gt;
Las regiones se combinan durante la búsqueda cuando el candidato todavía es demasiado pequeño. No se juntan todas las regiones reemplazables sin tener en cuenta el tamaño solicitado.&lt;br /&gt;
&lt;br /&gt;
=== Reemplazar y dividir la región elegida ===&lt;br /&gt;
&lt;br /&gt;
Una vez elegido el espacio:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemovePosesInSpace&amp;lt;/code&amp;gt; recorre sus regiones y retira de la tabla hash las poses que haya que reemplazar.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_RemoveSpace&amp;lt;/code&amp;gt; representa el espacio elegido como una región libre, actualizando sus extremos.&lt;br /&gt;
# Se busca una entrada hash libre y se guarda el bloque de comienzo en &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicPoseHashmap_Add&amp;lt;/code&amp;gt; registra la pose.&lt;br /&gt;
# &amp;lt;code&amp;gt;VRAMMap_AddPoseInSpace&amp;lt;/code&amp;gt; escribe el índice hash de la pose y el comienzo de su región en el primer y último bloque.&lt;br /&gt;
# Si sobran bloques, crea otra región libre con el resto.&lt;br /&gt;
&lt;br /&gt;
Si una región de 6 bloques aloja una pose de 4, quedan una región ocupada de 4 y una libre de 2. No se mueven las demás poses para compactar VRAM.&lt;br /&gt;
&lt;br /&gt;
=== DynamicRoutine: preparar las transferencias de la pose ===&lt;br /&gt;
&lt;br /&gt;
En este punto ya se eligió el espacio y se registró la pose. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; convierte esa asignación en solicitudes de transferencia.&lt;br /&gt;
&lt;br /&gt;
Utiliza estos datos:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Dato !! Cantidad consultada por pose !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Bloque de comienzo || 1 byte || Lugar elegido por el mapa de VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; || 2 bytes de una tabla de 256 bytes || Convierte uno de los 128 bloques en un desplazamiento de VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || 3 bytes || Dirección completa de los datos de la pose en ROM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || 4 bytes: dos valores de 2 || Cantidad de bytes del primer y del segundo tramo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || 2 bytes || Desplazamiento de VRAM para el segundo tramo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Convertir el bloque en una dirección de VRAM ====&lt;br /&gt;
&lt;br /&gt;
Los bloques de 16×16 no se convierten simplemente en un desplazamiento lineal de bytes. Cada uno utiliza tiles de 8×8 distribuidos en las filas de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OffsetToVRAMOffset&amp;lt;/code&amp;gt; contempla esa distribución. Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bloque !! Desplazamiento !! Dirección de VRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas direcciones de VRAM están expresadas en palabras de 2 bytes, no en bytes. La rutina suma la base &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; utilizada para los gráficos de sprites.&lt;br /&gt;
&lt;br /&gt;
==== Procesar los tramos y sus filas ====&lt;br /&gt;
&lt;br /&gt;
# Obtiene el origen desde &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Procesa los bytes del primer tramo mediante &amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Si el segundo tramo tiene tamaño 0, termina.&lt;br /&gt;
# Si existe, adelanta el origen la cantidad de bytes del primer tramo.&lt;br /&gt;
# Suma &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; al desplazamiento de VRAM y procesa el segundo tramo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutineLine&amp;lt;/code&amp;gt; divide cada tramo según las filas y el punto de comienzo. Para un destino V expresado en palabras de VRAM, prepara:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Final de la primera fila = (V + $0100) AND $FF00&lt;br /&gt;
Bytes hasta ese final = (final de la primera fila - V) × 2&lt;br /&gt;
Destino de la segunda parte = final de la primera fila + $0100&lt;br /&gt;
Bytes de la segunda parte de un grupo = $0200 - bytes de la primera&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los tamaños son cantidades de bytes, mientras que los destinos de VRAM están expresados en palabras. Por eso se multiplica por 2 al calcular cuántos datos caben hasta el final de una fila.&lt;br /&gt;
&lt;br /&gt;
La rutina utiliza tres recorridos:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt;: añade una solicitud final con los bytes restantes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLinesWithEndLine&amp;lt;/code&amp;gt;: añade dos solicitudes para los datos restantes, cada una con su destino y cantidad de bytes.&lt;br /&gt;
* &amp;lt;code&amp;gt;.TwoLines&amp;lt;/code&amp;gt;: añade dos solicitudes que suman &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, avanza el origen y los destinos y repite con los datos que faltan.&lt;br /&gt;
&lt;br /&gt;
Hay un caso directo antes del recorrido general: si el destino comienza en un límite de &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; palabras y el tramo tiene al menos &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes, la rutina utiliza &amp;lt;code&amp;gt;.EndLine&amp;lt;/code&amp;gt; para preparar la copia del tramo completo en una solicitud.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, un tramo de &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes que comienza en &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; se divide así:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Solicitud !! Origen !! Destino VRAM !! Bytes&lt;br /&gt;
|-&lt;br /&gt;
| Primera || Comienzo del tramo || &amp;lt;code&amp;gt;$6020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt;: 448&lt;br /&gt;
|-&lt;br /&gt;
| Segunda || Comienzo del tramo + &amp;lt;code&amp;gt;$01C0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0040&amp;lt;/code&amp;gt;: 64&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las dos solicitudes copian los 512 bytes del tramo, respetando los destinos que calcula la distribución de filas. No son dos copias completas de la pose.&lt;br /&gt;
&lt;br /&gt;
Cada solicitud utiliza estas tablas:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Por cada solicitud añadida aumenta &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
La cantidad total de bytes de la pose ya se comprobó y se añadió a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;TakeDynamicRequest&amp;lt;/code&amp;gt;. Esta parte divide esa carga en transferencias; no vuelve a contar la pose completa por cada solicitud.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; &#039;&#039;&#039;no ejecuta DMA&#039;&#039;&#039;. Deja las solicitudes preparadas para que &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt; las copie durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== Qué conserva el sprite ===&lt;br /&gt;
&lt;br /&gt;
Las rutinas de sprites guardan el índice hash de la pose utilizable, no una copia independiente de sus gráficos. Ese índice permite consultar su bloque de VRAM y mantener actualizado su tiempo de uso.&lt;br /&gt;
&lt;br /&gt;
Si una pose nueva no puede cargarse:&lt;br /&gt;
&lt;br /&gt;
* Si existe una pose anterior válida, se mantiene y se actualiza su tiempo de uso para protegerla.&lt;br /&gt;
* Si nunca hubo una pose válida, no se debe dibujar como si la solicitud hubiera tenido éxito.&lt;br /&gt;
* En las llamadas con soporte para mantener la anterior, el carry puede indicar que todavía hay una pose utilizable aunque no se haya completado el cambio.&lt;br /&gt;
&lt;br /&gt;
La animación y el movimiento siguen siendo responsabilidad del sprite. La caché se ocupa de reutilizar o preparar los gráficos solicitados.&lt;br /&gt;
&lt;br /&gt;
== Efectos de paleta: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
El sistema conserva los colores originales para poder cambiar de efecto, combinarlo con otro o volver a la paleta sin efecto. No debe utilizar el resultado ya afectado como si fuera la paleta original.&lt;br /&gt;
&lt;br /&gt;
=== Buffers de colores ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o buffer !! Bytes totales !! Bytes por valor !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 || 2 por color || Colores de base en formato SNES, con 2 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 || 3 por color || Base separada en rojo, verde y azul, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 || 3 por color || Base separada en tono, saturación y luminosidad, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 || 2 por color || Resultado en formato SNES, listo para solicitar su copia a CGRAM. Corresponde al buffer de paletas del juego.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Indicadores de cada paleta ===&lt;br /&gt;
&lt;br /&gt;
Cada bit de estos indicadores corresponde a una paleta. Las variables &amp;lt;code&amp;gt;BG&amp;lt;/code&amp;gt; cubren 0-7 y las &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt; cubren 8-F.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variables !! Bytes totales !! Bytes por valor !! Qué indican&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si ya se preparó la base de colores en formato SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparada la conversión de la base a RGB.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparada la conversión de la base a HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 por variable; 2 entre ambas || 1; un bit por paleta || Si está preparado el resultado del efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos indicadores evitan repetir conversiones y cálculos que siguen siendo válidos.&lt;br /&gt;
&lt;br /&gt;
=== Preparar una base ===&lt;br /&gt;
&lt;br /&gt;
# Se comprueba si la paleta ya tiene una base registrada.&lt;br /&gt;
# Si no la tiene, se obtienen los colores del buffer del juego. Una carga explícita, como &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, puede proporcionar esa base directamente.&lt;br /&gt;
# Se comprueba si el efecto necesita RGB o HSL.&lt;br /&gt;
# Si falta esa conversión, se prepara y se marca como disponible.&lt;br /&gt;
&lt;br /&gt;
Si solo cambia el efecto, la base puede seguir siendo válida. Si cambian los colores originales, las llamadas de carga actualizan la base e invalidan las conversiones y resultados que deben calcularse otra vez.&lt;br /&gt;
&lt;br /&gt;
=== Datos de un efecto ===&lt;br /&gt;
&lt;br /&gt;
El ID permite consultar las tablas generadas durante la instalación:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt;: cálculo que debe realizarse.&lt;br /&gt;
* &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt;: valores de los canales o dirección de la paleta de destino de una transición.&lt;br /&gt;
* &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt;: cuánto se aplica cada cambio.&lt;br /&gt;
&lt;br /&gt;
Los canales utilizan valores de 0 a 31. Los ratios van de 0 a 127: 0 conserva el origen y 127 aplica por completo el cambio elegido.&lt;br /&gt;
&lt;br /&gt;
Los cálculos se realizan fuera de NMI. NMI realiza la transferencia de los colores resultantes.&lt;br /&gt;
&lt;br /&gt;
=== Efecto global ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Bytes totales !! Bytes por valor !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 || 2 || Selecciona el efecto global. El valor 0 permite restaurar los colores de base.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta || Selecciona las paletas 0-7 que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 || 1; un bit por paleta || Selecciona las paletas 8-F que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 32 || 2 || Guarda el último ID global procesado por cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 || 1 || Controla la participación del color fijo y el color 0,0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para cada paleta habilitada, el administrador:&lt;br /&gt;
&lt;br /&gt;
# Comprueba si necesita actualizar el resultado del efecto.&lt;br /&gt;
# Prepara la base RGB o HSL si todavía falta.&lt;br /&gt;
# Calcula el efecto si el resultado anterior ya no sirve.&lt;br /&gt;
# Prepara los colores en formato SNES y solicita su transferencia.&lt;br /&gt;
# Confirma el ID procesado cuando la carga correspondiente se acepta.&lt;br /&gt;
&lt;br /&gt;
Si se mantiene el mismo efecto y no cambió la base, no hace falta calcularlo otra vez. Al cambiar el ID global se invalidan los resultados anteriores, no necesariamente las bases RGB y HSL.&lt;br /&gt;
&lt;br /&gt;
El ID global 0 también requiere una actualización: el sistema debe cargar de nuevo los colores de base para quitar el efecto anterior.&lt;br /&gt;
&lt;br /&gt;
=== Efecto local y concatenación ===&lt;br /&gt;
&lt;br /&gt;
Un recurso puede tener un efecto propio y recibir también el global. Por ejemplo, un sprite puede cambiar de tono y después oscurecerse junto con el nivel.&lt;br /&gt;
&lt;br /&gt;
El orden es:&lt;br /&gt;
&lt;br /&gt;
# Preparar el resultado del efecto local.&lt;br /&gt;
# Utilizarlo como base para el efecto global mediante la llamada de concatenación.&lt;br /&gt;
# Calcular el efecto global sobre esa base.&lt;br /&gt;
# Cargar el resultado combinado, sin mostrar antes la versión que solo tiene el efecto local.&lt;br /&gt;
&lt;br /&gt;
* La concatenación RGB se utiliza con efectos RGB.&lt;br /&gt;
* La concatenación HSL se utiliza con efectos HSL.&lt;br /&gt;
* Los recursos que comparten un destino de CGRAM comparten sus colores. Para mostrar dos efectos locales distintos, necesitan destinos que permitan mantener ambos resultados.&lt;br /&gt;
&lt;br /&gt;
=== Si no se acepta la transferencia ===&lt;br /&gt;
&lt;br /&gt;
* Calcular el efecto no significa que ya esté en CGRAM.&lt;br /&gt;
* Si la transferencia no se acepta, el administrador puede volver a intentar la actualización.&lt;br /&gt;
* Cuando corresponde, se mantiene el resultado anterior utilizable hasta poder sustituirlo.&lt;br /&gt;
* No se deben cargar primero los colores originales sin efecto: podrían verse así durante un frame antes del resultado correcto.&lt;br /&gt;
&lt;br /&gt;
== Cómo trabajan juntos ==&lt;br /&gt;
&lt;br /&gt;
El recorrido de un sprite dinámico reúne estas tareas:&lt;br /&gt;
&lt;br /&gt;
# Su lógica elige la pose y la versión de paleta.&lt;br /&gt;
# La asignación busca una paleta utilizable y prepara los colores si hace falta.&lt;br /&gt;
# La caché protege la pose ya cargada o prepara la carga de una nueva.&lt;br /&gt;
# El dibujo escribe los datos de sus piezas en los buffers OAM.&lt;br /&gt;
# El administrador de efectos prepara los cambios globales pendientes.&lt;br /&gt;
# NMI realiza las transferencias de gráficos y colores solicitadas.&lt;br /&gt;
&lt;br /&gt;
Compartir gráficos, compartir una paleta y compartir una rutina de dibujo son tres cosas distintas. Dynamic Xtreme puede aprovechar cada una sin obligar a que los recursos compartan también las demás.&lt;br /&gt;
&lt;br /&gt;
== Lecturas relacionadas ==&lt;br /&gt;
&lt;br /&gt;
* [[es/Dynamic_Xtreme|Artículo principal]]: funcionalidades y compatibilidad.&lt;br /&gt;
* [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_sprite_creation_guide|Creación de sprites dinámicos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_UberASM_guide|Dynamic Xtreme con UberASM]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_ASM_API|API ASM]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21372</id>
		<title>es/Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21372"/>
		<updated>2026-10-25T02:21:37Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo funciona Dynamic Xtreme, desde la preparación de los recursos al instalarlo hasta la carga y el dibujo de una pose durante el juego.&lt;br /&gt;
&lt;br /&gt;
== Qué prepara la instalación ==&lt;br /&gt;
&lt;br /&gt;
Antes de que un sprite pueda usar sus gráficos o una paleta, Dynamic Xtreme tiene que guardarlos en la ROM y preparar la información para encontrarlos. Lo mismo ocurre con cualquier otro recurso dinámico que hayas añadido.&lt;br /&gt;
&lt;br /&gt;
Para hacerlo, la herramienta lee los DynamicInfo, DrawInfo y PaletteEffect. Cada archivo aporta una parte distinta: qué recursos se van a cargar, cómo se dibujan las poses y qué cambios de color se pueden aplicar.&lt;br /&gt;
&lt;br /&gt;
Gracias a esta preparación se generan defines en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permiten utilizar los recursos y ejecutar fácilmente las rutinas necesarias.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: recursos y datos de carga ===&lt;br /&gt;
&lt;br /&gt;
Un DynamicInfo reúne los gráficos de poses, las paletas y los recursos generales que necesita un sprite u otro código. Si incluye gráficos de poses dinámicas, la herramienta los organiza para que puedan cargarse con la distribución de tiles que espera el sistema.&lt;br /&gt;
&lt;br /&gt;
Por cada pose guarda varios datos en tablas separadas. Todas mantienen el mismo orden: la entrada de una pose en una tabla corresponde a esa misma pose en las demás.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || La cantidad de datos que utiliza cada pose, en bytes. Se utiliza para comprobar si su carga cabe en el presupuesto del frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || Cuántos bloques de 16×16 hay que reservar en VRAM para la pose. No siempre coincide exactamente con los bytes que se copian, porque una pieza incompleta también puede necesitar un bloque de espacio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || La dirección de los gráficos de cada pose en ROM. Incluye el banco, de modo que el código de carga pueda encontrar su origen completo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || Dos tamaños por pose, correspondientes a los dos tramos en que pueden dividirse sus gráficos. La rutina de carga utiliza esos tamaños para repartirlos correctamente en VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || El desplazamiento en VRAM desde el comienzo del primer tramo hasta el comienzo del segundo. Permite colocar el segundo tramo donde corresponde, aunque el primero termine con una fila incompleta.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas describen todas las poses instaladas, no solo las que están en pantalla. Más adelante, la caché guarda por separado cuáles están cargadas y dónde quedaron.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si se solicita una pose que todavía no está en VRAM, el sistema consulta cuántos bytes necesita cargar, busca espacio para sus bloques y utiliza la dirección y los datos de sus tramos para preparar la carga.&lt;br /&gt;
&lt;br /&gt;
==== Tablas de paletas ====&lt;br /&gt;
&lt;br /&gt;
Las paletas declaradas en los DynamicInfo se reúnen en &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. Esta tiene dos partes:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; guarda el ID de cada paleta.&lt;br /&gt;
* &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; guarda dónde están sus colores en ROM.&lt;br /&gt;
&lt;br /&gt;
Las dos listas siguen el orden de las paletas de los DynamicInfo. El define de offset de cada DynamicInfo indica dónde comienza su lista dentro de ellas. Al elegir una versión, el sistema suma ese índice al offset y obtiene tanto el ID como la dirección de los colores elegidos.&lt;br /&gt;
&lt;br /&gt;
El ID permite reconocer y compartir una paleta; la dirección permite cargarla. No son el número de paleta de pantalla: una misma paleta instalada puede terminar, por ejemplo, en la paleta 9 o en la C según la asignación.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y defines ====&lt;br /&gt;
&lt;br /&gt;
Los archivos declarados en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; se guardan en ROM. Su dirección y la cantidad de bytes que ocupan pueden consultarse mediante los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Por ejemplo, para &amp;lt;code&amp;gt;my_resource.bin&amp;lt;/code&amp;gt; se generan:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt;: dirección del recurso en ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt;: cantidad de bytes que ocupa.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt;: ID del recurso.&lt;br /&gt;
&lt;br /&gt;
El nombre se normaliza en PascalCase: se eliminan espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: datos y rutinas de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El DrawInfo describe cómo está formada una pose: qué tiles tiene, dónde se coloca cada uno, qué tamaño utiliza y cómo cambia al voltearse.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, Dynamic Xtreme genera rutinas de dibujo optimizadas según los parámetros que utilizan los tiles. Tiene en cuenta, por ejemplo, si necesitan desplazamientos X e Y, si comparten el mismo tamaño, si utilizan propiedades comunes y si requieren volteos.&lt;br /&gt;
&lt;br /&gt;
De esta forma, la rutina realiza el trabajo que necesita ese dibujo sin añadir el manejo de opciones que no utiliza. Varias poses pueden compartirla si necesitan el mismo tratamiento; eso no significa que compartan también sus gráficos o su ID.&lt;br /&gt;
&lt;br /&gt;
La relación entre una pose y su dibujo se guarda en estas tablas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || Dónde comienzan los datos de la pose dentro de las tablas de su rutina de dibujo. Así se localizan sus tiles y desplazamientos sin recorrer las poses anteriores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || La cantidad de tiles de la pose menos uno. Una pose de cuatro tiles guarda 3; la rutina utiliza ese valor para recorrer sus piezas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || Qué rutina de dibujo utiliza cada pose. Las poses con características compatibles pueden apuntar al mismo ID de rutina.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || Las direcciones de las rutinas de dibujo. El ID de rutina permite encontrar aquí el código que debe ejecutarse.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada rutina tiene, además, las tablas que necesitan sus poses:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos !! Qué describen&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || Los números de tile que forman la pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || Las propiedades de cada pieza, como los volteos y su prioridad respecto a las capas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || La posición de cada tile respecto al punto de origen de la pose.&lt;br /&gt;
|-&lt;br /&gt;
| Tablas de desplazamientos para los volteos || Las posiciones que deben utilizarse al voltear la pose cuando necesita una distribución distinta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || El tamaño de cada tile: 8×8 o 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
No todas estas tablas tienen que aparecer en todas las rutinas. Si un dato es igual para todas las piezas o puede obtenerse de un valor común, la herramienta puede generar una rutina que lo utilice directamente.&lt;br /&gt;
&lt;br /&gt;
La optimización se hace durante la instalación. Si todos los tiles tienen el mismo tamaño, por ejemplo, la rutina puede utilizar ese valor común sin leer un tamaño distinto para cada pieza.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: datos de los efectos ===&lt;br /&gt;
&lt;br /&gt;
Un archivo PaletteEffect contiene una lista de cambios de color. La instalación les asigna IDs y guarda sus datos en &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Como en las tablas de poses, los datos de cada efecto mantienen la misma posición en las distintas listas. Los IDs de efectos comienzan en 1; el ID 0 se utiliza para indicar que no hay efecto global.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parte de la tabla !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || La cantidad de efectos instalados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || El tipo de cada efecto, por ejemplo &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Indica qué cálculo debe realizarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || Los valores de los canales que utiliza el efecto. En una transición, estos tres bytes guardan la dirección de la paleta de destino, no valores de canales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || Cuánto se aplica el cambio en cada componente. Van de 0 a 127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Si el efecto es una transición hacia otra paleta, la herramienta también prepara esa paleta. Convierte sus colores al formato RGB o HSL que necesita la transición y los guarda en ROM. Durante el juego se puede utilizar ese destino sin tener que convertirlo de nuevo en cada llamada.&lt;br /&gt;
&lt;br /&gt;
Estas paletas de transición son distintas de las paletas normales que se cargan a CGRAM: contienen tres componentes por color y se utilizan para calcular el efecto.&lt;br /&gt;
&lt;br /&gt;
=== Cómo encuentra el código los recursos instalados ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; publica los IDs, direcciones, tamaños y offsets que necesitan los recursos. Por ejemplo, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifica una pose y &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifica el primer efecto de un archivo.&lt;br /&gt;
&lt;br /&gt;
Los nombres se normalizan en PascalCase: se eliminan separadores como espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra. &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, por ejemplo, pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También se genera &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, que guarda las direcciones de los bloques donde se insertaron los recursos. La herramienta utiliza esa información para localizar los datos de una instalación anterior al reinstalar.&lt;br /&gt;
&lt;br /&gt;
Una reinstalación puede cambiar IDs y direcciones. Por eso hay que volver a insertar los sprites, bloques y códigos UberASM que utilizan los defines generados.&lt;br /&gt;
&lt;br /&gt;
== El trabajo de cada frame ==&lt;br /&gt;
&lt;br /&gt;
En la lógica principal se ejecutan el jugador, los sprites y los demás códigos del modo de juego. Los que utilizan Dynamic Xtreme solicitan las poses y paletas que necesitan, preparan los efectos locales y llaman a las rutinas de dibujo. Las cargas que se aceptan quedan anotadas para transferir sus datos durante NMI.&lt;br /&gt;
&lt;br /&gt;
Al terminar esa lógica, el código de game mode de Dynamic Xtreme realiza las tareas que correspondan a las opciones habilitadas: prepara las actualizaciones de VRAM de la optimización de Kevin, mantiene el estado de las paletas y calcula los efectos globales pendientes.&lt;br /&gt;
&lt;br /&gt;
Después, durante NMI, se ejecutan las transferencias preparadas: los gráficos se copian a VRAM y los colores a CGRAM. También se reinicia el contador de datos y se actualizan los relojes del sistema para el siguiente ciclo de trabajo.&lt;br /&gt;
&lt;br /&gt;
El orden que seguiremos para explicarlo es, por tanto, &#039;&#039;&#039;lógica principal → tareas al terminar el game mode → transferencias durante NMI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Lógica principal ===&lt;br /&gt;
&lt;br /&gt;
Cada recurso decide qué necesita. Un sprite puede cambiar de pose, una animación puede pedir nuevos gráficos y un código UberASM puede cargar una paleta o seleccionar un efecto.&lt;br /&gt;
&lt;br /&gt;
Si la pose solicitada ya está cargada, Dynamic Xtreme actualiza su tiempo de último uso para protegerla del reemplazo y no vuelve a cargar sus gráficos. Si no está cargada, comprueba el presupuesto de datos del frame y busca espacio disponible en VRAM antes de preparar su carga.&lt;br /&gt;
&lt;br /&gt;
El dibujo también se prepara en esta parte: las rutinas escriben en los buffers OAM la posición, los tiles y las propiedades de las piezas que se mostrarán.&lt;br /&gt;
&lt;br /&gt;
Una solicitud puede rechazarse, por ejemplo si no queda presupuesto para sus datos. El recurso que la pidió debe comprobar el resultado y decidir si conserva lo anterior o vuelve a intentarlo después. Una carga rechazada no queda guardada automáticamente para otro frame.&lt;br /&gt;
&lt;br /&gt;
=== Tareas de game mode ===&lt;br /&gt;
&lt;br /&gt;
En esta parte se realizan las siguientes tareas, según las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antes de ejecutar la lógica del juego:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitado &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;, se ejecuta la rutina del control aquí en lugar de hacerlo en NMI.&lt;br /&gt;
# Se comprueba si Dynamic Xtreme debe funcionar en el game mode actual. Si no debe hacerlo, se reinician sus variables. Esto ocurre cada frame que se permanezca en un modo no permitido.&lt;br /&gt;
&lt;br /&gt;
Después se ejecuta la lógica normal del juego, incluidos los sprites y los códigos que solicitan cargas o cambios de paleta.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cuando termina esa lógica:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitada la optimización de VRAM de Kevin, se ajustan los destinos de las actualizaciones de Lunar Magic antes de que se transfieran.&lt;br /&gt;
# Se ponen en 0 los indicadores de actualización de las paletas y se resta 1 a sus temporizadores de protección si todavía son mayores que 0. Esta parte se omite durante la pausa y en los modos no permitidos.&lt;br /&gt;
# Se aplican los efectos globales a las paletas que necesitan actualizarse y se preparan las transferencias de sus colores. Esta parte también se omite si la comprobación anterior impide continuar.&lt;br /&gt;
&lt;br /&gt;
Las copias a VRAM y CGRAM se realizan después, durante NMI. Aquí se deja preparado lo que se va a copiar.&lt;br /&gt;
&lt;br /&gt;
=== Transferencias durante NMI ===&lt;br /&gt;
&lt;br /&gt;
NMI es una interrupción que SNES puede generar al comenzar VBlank, después de dibujar la parte visible de la pantalla. El juego aprovecha ese intervalo para actualizar gráficos, colores y otros datos de video.&lt;br /&gt;
&lt;br /&gt;
En los modos permitidos, la rutina de Dynamic Xtreme reinicia &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; y actualiza sus relojes. Después ejecuta las transferencias de gráficos pendientes y luego las de paletas. Si corresponde, también actualiza el color 0,0 preparado por el sistema de efectos.&lt;br /&gt;
&lt;br /&gt;
Para realizar las copias se utiliza DMA. NMI lee cada carga de las listas, configura desde dónde se copiarán los datos, cuántos bytes se copiarán y dónde se colocarán, y ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
El tiempo de VBlank es limitado y SMW también lo necesita para sus actualizaciones de pantalla. Para limitar la cantidad de datos enviados en un frame y evitar flickering, Dynamic Xtreme utiliza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, que cuenta los bytes de las cargas solicitadas, y &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, que establece el límite permitido. Antes de aceptar una carga normal, se comprueba que sus bytes no hagan superar ese límite.&lt;br /&gt;
&lt;br /&gt;
==== Las listas de transferencias ====&lt;br /&gt;
&lt;br /&gt;
Cada transferencia guarda el origen de los datos, su banco, la cantidad de bytes y el destino en VRAM o CGRAM.&lt;br /&gt;
&lt;br /&gt;
Al realizar las copias, NMI recorre las listas desde la última entrada hacia la primera y después las vacía. Esto no borra los gráficos o colores cargados: permanecen en su destino hasta que otro código los cambie.&lt;br /&gt;
&lt;br /&gt;
La lista de VRAM utiliza 0 cuando no tiene entradas. La de CGRAM utiliza &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, porque guarda el índice de la última entrada en lugar de guardar directamente su cantidad.&lt;br /&gt;
&lt;br /&gt;
Si dos códigos escriben sobre el mismo destino, deben coordinar sus cargas. El orden de las solicitudes no debe utilizarse como sustituto de decidir qué recurso puede ocupar cada espacio.&lt;br /&gt;
&lt;br /&gt;
Normalmente, el recurso se lee desde ROM. Si el recurso se encuentra en un buffer en RAM, el usuario debe conservar su contenido hasta que NMI realice la transferencia. Por ejemplo, si prepara una paleta en RAM, no debe modificar ni reutilizar ese buffer antes de que se copie. La lista guarda su dirección, no una copia de sus datos; Dynamic Xtreme no protege el buffer contra cambios realizados por otros códigos.&lt;br /&gt;
&lt;br /&gt;
==== Presupuesto de datos ====&lt;br /&gt;
&lt;br /&gt;
Las macros de transferencia, como &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt;, comprueban cuántos bytes se han solicitado mediante &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;. Si al añadir la nueva carga se supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, la rechazan. Si la aceptan, suman sus bytes al contador.&lt;br /&gt;
&lt;br /&gt;
El límite predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Su objetivo es evitar flickering por enviar demasiados datos en un mismo frame. Es un límite de cantidad de datos, no una medida exacta del tiempo que tarda cada transferencia.&lt;br /&gt;
&lt;br /&gt;
Estas macros tienen variantes como &amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ForcedTransferToCGRAM()&amp;lt;/code&amp;gt;, que aceptan la carga sin comprobar si supera el límite. Sus bytes también se suman a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, por lo que reducen lo que queda disponible para las siguientes cargas normales. Se utilizan para cargas prioritarias, como las del jugador; usarlas no evita el flickering si se solicita una cantidad excesiva de datos.&lt;br /&gt;
&lt;br /&gt;
==== Los dos relojes ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_Timer: protección de las solicitudes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza cuando se ejecuta la parte de NMI de Dynamic Xtreme. Además de medir cuánto lleva una pose sin utilizarse, sirve para evitar que un recurso repita sus solicitudes antes de que se procesen las anteriores.&lt;br /&gt;
&lt;br /&gt;
No siempre hay un ciclo de lógica por cada ejecución completa de NMI. Durante slowdown, SMW puede ejecutar una versión reducida de NMI, y puede haber dos ciclos de lógica sin que entre ellos se hayan procesado las listas de transferencias de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Sin una protección, un recurso podría añadir otra vez sus cargas a esas listas. Las solicitudes repetidas ocuparían más espacio y podrían provocar flickering.&lt;br /&gt;
&lt;br /&gt;
Para evitarlo, las rutinas con esta protección comparan &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; con un valor guardado por el recurso, normalmente llamado &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt;. Si coinciden, el recurso ya hizo su intento con ese valor del reloj y no debe añadir de nuevo las cargas. Si son distintos, guarda el valor actual y puede realizar la nueva solicitud.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; continúa avanzando durante la pausa cuando se ejecuta esa parte de NMI.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_SyncTimer: animaciones sincronizadas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
La función principal de &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; es dar a los sprites un reloj común para sus animaciones. Por ejemplo, varios sprites que utilizan las mismas poses pueden calcular con este reloj qué pose les corresponde cada cuatro frames.&lt;br /&gt;
&lt;br /&gt;
Así todos cambian al mismo tiempo y solicitan la misma pose. La primera solicitud puede necesitar cargarla; las demás la reutilizan sin programar otra carga de sus gráficos. Esto ahorra transferencias DMA y datos enviados por frame.&lt;br /&gt;
&lt;br /&gt;
Si cada sprite llevara un reloj independiente, podrían terminar usando poses distintas de la misma animación al mismo tiempo y necesitar más cargas y espacio de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; se detiene durante la pausa y cuando se congela la acción, para que las animaciones sincronizadas también se detengan.&lt;br /&gt;
&lt;br /&gt;
== Carga de gráficos: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; guarda en RAM una lista de solicitudes de carga. Durante NMI se recorren esas solicitudes y se copian sus datos a VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Variables de la lista ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || Cantidad de solicitudes pendientes. El valor 0 indica que la lista está vacía.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || Dirección de origen de cada solicitud, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || Cantidad de bytes que se copiarán.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || Dirección de destino en VRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las tablas mantienen el mismo orden: la primera entrada de cada tabla pertenece a la primera solicitud, la segunda a la segunda, etc. Cada entrada de estas tablas ocupa 2 bytes, por lo que se avanza con desplazamientos de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt;, etc.&lt;br /&gt;
&lt;br /&gt;
Estos nombres representan direcciones de RAM calculadas en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus direcciones pueden cambiar según la configuración y las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
=== Añadir una solicitud ===&lt;br /&gt;
&lt;br /&gt;
La macro &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; realiza los siguientes pasos:&lt;br /&gt;
&lt;br /&gt;
# Calcula cuántos bytes habría en total al añadir la nueva carga a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Compara el resultado con &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;. Si lo supera, devuelve el carry desactivado y no añade la solicitud.&lt;br /&gt;
# Utiliza &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para encontrar la siguiente entrada y aumenta ese contador en 1.&lt;br /&gt;
# Guarda el origen, banco, cantidad de bytes y destino en las tablas.&lt;br /&gt;
# Actualiza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; con los bytes de la carga y devuelve el carry activado.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; guarda los mismos datos, pero no comprueba el límite de bytes. Las variantes &amp;lt;code&amp;gt;FromAddr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; facilitan obtener el origen desde una dirección completa o desde los defines de un recurso.&lt;br /&gt;
&lt;br /&gt;
Añadir una solicitud no copia los gráficos inmediatamente: deja la información preparada para NMI.&lt;br /&gt;
&lt;br /&gt;
=== Ejecutar las solicitudes durante NMI ===&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;VRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Lee &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt;. Si es 0, termina porque no hay solicitudes.&lt;br /&gt;
# Calcula el desplazamiento de la última entrada: &amp;lt;code&amp;gt;(Length - 1) × 2&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Lee su origen, banco y cantidad de bytes, y los coloca en los registros de DMA.&lt;br /&gt;
# Escribe el destino de VRAM en &amp;lt;code&amp;gt;$2116-$2117&amp;lt;/code&amp;gt; e inicia la transferencia mediante &amp;lt;code&amp;gt;$420B&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Retrocede 2 bytes para procesar la solicitud anterior. Repite hasta completar la primera.&lt;br /&gt;
# Escribe 0 en &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; para indicar que la lista está vacía.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;La lista se ejecuta del final al inicio.&#039;&#039;&#039; No hace falta borrar todos sus datos al terminar: al quedar su largo en 0, la próxima solicitud volverá a utilizar la primera entrada.&lt;br /&gt;
&lt;br /&gt;
=== Animaciones con un destino fijo ===&lt;br /&gt;
&lt;br /&gt;
El código de una animación debe:&lt;br /&gt;
&lt;br /&gt;
# Elegir la imagen que corresponde al paso actual.&lt;br /&gt;
# Calcular su dirección de origen.&lt;br /&gt;
# Solicitar la copia al destino de VRAM de la animación.&lt;br /&gt;
# Comprobar el carry. Si se rechaza la carga, conservar la imagen anterior y volver a intentarlo.&lt;br /&gt;
&lt;br /&gt;
El destino puede ser siempre el mismo. Lo que cambia es la imagen que se copia allí; la lista de transferencias no decide cuándo debe avanzar la animación.&lt;br /&gt;
&lt;br /&gt;
=== Carga de una pose dinámica ===&lt;br /&gt;
&lt;br /&gt;
Una pose puede necesitar varias transferencias para colocar sus datos en las filas correctas de VRAM. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; las prepara utilizando:&lt;br /&gt;
&lt;br /&gt;
* El lugar de VRAM que la caché eligió para la pose.&lt;br /&gt;
* &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt;: dirección de sus datos en ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt;: cantidad de bytes de sus tramos.&lt;br /&gt;
* &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt;: desplazamiento del segundo tramo.&lt;br /&gt;
&lt;br /&gt;
Buscar espacio y elegir qué poses reemplazar es trabajo de la caché. Esta rutina prepara las transferencias para el espacio ya elegido.&lt;br /&gt;
&lt;br /&gt;
== Carga y asignación de paletas: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
El sistema distingue dos valores:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID de paleta:&#039;&#039;&#039; identifica los colores guardados en ROM.&lt;br /&gt;
* &#039;&#039;&#039;Destino de pantalla:&#039;&#039;&#039; indica qué paleta de CGRAM utilizará esos colores.&lt;br /&gt;
&lt;br /&gt;
La asignación automática permite compartir colores entre sprites sin exigir un destino fijo para cada uno.&lt;br /&gt;
&lt;br /&gt;
=== Lista de cargas a CGRAM ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || Índice de la última solicitud pendiente. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; indica una lista vacía; 0 indica que hay una solicitud.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || Dirección de origen, sin el banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || Banco del origen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || Cantidad de bytes que se copiarán. Cada color ocupa 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || Primer color de destino en CGRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Durante NMI, &amp;lt;code&amp;gt;CGRAMDMA&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# Comienza por la última solicitud pendiente.&lt;br /&gt;
# Configura DMA con el origen y la cantidad de bytes de esa solicitud.&lt;br /&gt;
# Selecciona el primer color mediante &amp;lt;code&amp;gt;$2121&amp;lt;/code&amp;gt; y realiza la copia.&lt;br /&gt;
# Continúa con las solicitudes anteriores.&lt;br /&gt;
# Al terminar, escribe &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; también actualizan las copias de colores y el estado de efectos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Sin efecto global:&#039;&#039;&#039; solicitan la carga y actualizan los buffers de SMW. Así el juego no vuelve a utilizar colores anteriores durante la animación de victoria del goal.&lt;br /&gt;
* &#039;&#039;&#039;Con efecto global:&#039;&#039;&#039; guardan los colores originales y preparan el estado necesario para aplicarles el efecto antes de enviarlos a CGRAM.&lt;br /&gt;
&lt;br /&gt;
=== Asignación automática ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || Guarda el ID asignado a cada destino. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre y &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; una reservada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || Protege cada destino del reemplazo automático mientras está en uso.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || Indica qué paletas de sprites están asignadas con efecto global habilitado. Esta condición también se compara al compartir una asignación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La búsqueda sigue este orden:&lt;br /&gt;
&lt;br /&gt;
# Reutilizar una asignación con el mismo ID y una condición de efecto compatible.&lt;br /&gt;
# Si no existe, utilizar una entrada libre.&lt;br /&gt;
# Si no hay entradas libres, reemplazar una que no esté reservada y cuyo temporizador sea 0.&lt;br /&gt;
# Si no encuentra ninguna, indicar que la asignación falló.&lt;br /&gt;
&lt;br /&gt;
Mientras el recurso utiliza la paleta, mantiene su temporizador en 2. Llegar a 0 no borra los colores: la asignación puede reutilizarse si otro recurso todavía no la reemplazó.&lt;br /&gt;
&lt;br /&gt;
=== Asignación manual y versión ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Manual con carga:&#039;&#039;&#039; el código elige el destino y solicita sus colores.&lt;br /&gt;
* &#039;&#039;&#039;Manual sin carga:&#039;&#039;&#039; el código elige el destino y utiliza los colores que ya estaban preparados.&lt;br /&gt;
* &#039;&#039;&#039;Versión:&#039;&#039;&#039; selecciona una entrada de la lista de paletas del DynamicInfo. La última versión procesada permite comprobar si esa selección cambió.&lt;br /&gt;
&lt;br /&gt;
Dos recursos que elijan el mismo destino con colores distintos deben coordinarse. Mantener la protección de una paleta no significa volver a cargar sus colores.&lt;br /&gt;
&lt;br /&gt;
== Dibujo de poses: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
El dibujo prepara las piezas de una pose en OAM: qué tiles se muestran, dónde se colocan y qué propiedades utilizan. Los datos gráficos deben estar en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Pasos del dibujo ===&lt;br /&gt;
&lt;br /&gt;
# Busca la rutina y los datos de la pose mediante &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Obtiene la cantidad de piezas desde &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Calcula la posición de cada tile usando la posición del sprite, sus desplazamientos y los volteos que correspondan.&lt;br /&gt;
# Comprueba si la pieza puede verse y si queda espacio de OAM.&lt;br /&gt;
# Escribe su posición, número de tile, propiedades y tamaño en los buffers OAM.&lt;br /&gt;
&lt;br /&gt;
El número de tile depende del dibujo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Caso !! Cómo se obtiene el tile&lt;br /&gt;
|-&lt;br /&gt;
| Pose dinámica || Se ajusta al lugar de VRAM donde quedaron cargados sus gráficos.&lt;br /&gt;
|-&lt;br /&gt;
| Pose estática || Se utiliza su número de tile fijo.&lt;br /&gt;
|-&lt;br /&gt;
| Pose que utiliza un tile común || El código debe preparar &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; antes de llamar al dibujo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Prioridad y espacio disponible ===&lt;br /&gt;
&lt;br /&gt;
* En &#039;&#039;&#039;LoROM&#039;&#039;&#039;, el sistema lleva su propio control de entradas OAM disponibles.&lt;br /&gt;
* En &#039;&#039;&#039;SA-1&#039;&#039;&#039;, utiliza la integración con MaxTile.&lt;br /&gt;
* La &#039;&#039;&#039;prioridad de dibujo&#039;&#039;&#039; organiza las piezas de sprites. No es la misma propiedad que determina si un tile queda delante o detrás de las capas.&lt;br /&gt;
* Los &#039;&#039;&#039;límites por línea de pantalla&#039;&#039;&#039; de SNES siguen existiendo. Tener una pose cargada no garantiza que puedan verse todas sus piezas.&lt;br /&gt;
&lt;br /&gt;
== Jugador y Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
El jugador original tiene rutinas propias para elegir y cargar las piezas de sus poses. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; permite integrar ese trabajo con las cargas de Dynamic Xtreme y cambiar el origen de sus gráficos y paletas.&lt;br /&gt;
&lt;br /&gt;
Con el formato original, el juego sigue eligiendo las piezas de la pose. La rutina obtiene sus direcciones desde el origen configurado y compara esas direcciones con las anteriores para cargar las que hayan cambiado.&lt;br /&gt;
&lt;br /&gt;
Estas cargas utilizan transferencias forzadas y sus bytes también cuentan para las solicitudes normales posteriores. Así conservan su prioridad sin quedar fuera de la contabilidad del sistema.&lt;br /&gt;
&lt;br /&gt;
La paleta del jugador tiene un tratamiento especial: combina colores y selecciones del propio juego con el origen personalizado. No funciona simplemente como sustituir una paleta completa de un sprite cualquiera.&lt;br /&gt;
&lt;br /&gt;
El soporte para jugadores personalizados permite que otros sistemas administren de otra forma sus poses y dibujo. No convierte automáticamente cualquier spritesheet al formato del jugador original.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi también carga sus gráficos por piezas. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; permite cambiar su origen manteniendo la organización que esperan sus rutinas.&lt;br /&gt;
&lt;br /&gt;
El código calcula qué partes necesita y prepara sus cargas a los destinos correspondientes de VRAM. Como las del jugador, estas cargas tienen un tratamiento prioritario.&lt;br /&gt;
&lt;br /&gt;
Esta opción necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad. No permite evitar un conflicto del sistema del jugador habilitando únicamente las funciones de Yoshi.&lt;br /&gt;
&lt;br /&gt;
== Memoria y optimizaciones ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW mantiene en RAM gráficos originales del jugador, Yoshi y ciertas animaciones. En ROMs sin SA-1, esta opción adapta las cargas para leer esos datos desde ROM.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aprovecha la RAM recuperada para sus variables internas. No es un espacio que quede libre para que cualquier otro código escriba encima.&lt;br /&gt;
&lt;br /&gt;
SA-1 utiliza otras direcciones y desactiva esta opción. Los rangos están en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
Esta opción mueve el procesamiento del control desde NMI a la parte de game mode. El objetivo es dejar más tiempo para las actualizaciones de pantalla, no añadir un frame de retraso ni cambiar los botones que recibe el juego.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
El color fijo se utiliza en las mezclas de color de la consola. Para actualizarlo, el juego prepara sus componentes y los envía al registro correspondiente.&lt;br /&gt;
&lt;br /&gt;
La optimización reemplaza esa preparación por una secuencia más corta. El color sigue enviándose a la consola, pero necesita menos trabajo durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic utiliza listas llamadas stripe images para actualizar partes de los mapas de tiles. Esas listas incluyen tanto los datos como la información sobre sus destinos.&lt;br /&gt;
&lt;br /&gt;
La versión integrada de la optimización de Kevin prepara fuera de NMI parte del ajuste de esos destinos. Así deja menos trabajo de preparación para el momento de la transferencia.&lt;br /&gt;
&lt;br /&gt;
Esta opción sustituye el uso del parche original por separado. Además, no debe desinstalarse después de instalarla; hay que tenerlo en cuenta antes de activarla.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
La barra de estado original actualiza zonas concretas de VRAM. Esta opción prepara sus transferencias de forma más directa, reduciendo la configuración de DMA que necesita hacer durante NMI.&lt;br /&gt;
&lt;br /&gt;
No añade una barra nueva. Modifica la actualización de la original y, por eso, entra en conflicto con recursos que la reemplazan, modifican o eliminan.&lt;br /&gt;
&lt;br /&gt;
== Sprites dinámicos: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
El sistema utiliza el espacio disponible de VRAM como una caché de poses. Conserva las que ya cargó para reutilizarlas y reemplaza las que han dejado de utilizarse cuando hace falta espacio.&lt;br /&gt;
&lt;br /&gt;
Si varios sprites solicitan la misma pose, comparten sus gráficos en VRAM. Cada uno puede dibujarla en su propia posición. La comparación se hace por ID: gráficos visualmente iguales con IDs distintos no se consideran necesariamente la misma pose.&lt;br /&gt;
&lt;br /&gt;
=== Tablas de las poses cargadas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o tabla !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || Cantidad de poses registradas en la caché.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || Cantidad de poses de cada grupo de búsqueda por hash.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || ID de cada pose registrada. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica una entrada libre.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || Bloque de VRAM donde comienza la pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || Valor de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; de la última vez que se utilizó esa pose.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas describen las poses registradas durante el juego. No son las tablas de datos de todas las poses instaladas en ROM.&lt;br /&gt;
&lt;br /&gt;
=== Si la pose ya está cargada ===&lt;br /&gt;
&lt;br /&gt;
# Se calcula un índice de búsqueda a partir del ID solicitado.&lt;br /&gt;
# Se busca en la tabla hash de 128 entradas y se compara el ID completo para confirmar que es la pose correcta.&lt;br /&gt;
# Se escribe el valor actual de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; en su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt;.&lt;br /&gt;
# No se programa otra transferencia de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
Actualizar el tiempo de último uso protege la pose del reemplazo mientras los recursos la siguen utilizando.&lt;br /&gt;
&lt;br /&gt;
=== Si la pose no está cargada ===&lt;br /&gt;
&lt;br /&gt;
# Se consulta &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; para conocer cuántos bytes hay que cargar.&lt;br /&gt;
# Se comprueba si esos bytes caben en &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, teniendo en cuenta &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Se consulta &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; y se busca espacio para los bloques que necesita.&lt;br /&gt;
# Se eliminan de la caché las poses que deban reemplazarse en el espacio elegido.&lt;br /&gt;
# Se registra el nuevo ID, su bloque de VRAM y su tiempo de último uso, y se actualiza la cantidad de datos del frame.&lt;br /&gt;
# &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; prepara las transferencias de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
Si no hay presupuesto o espacio adecuado, se indica que la solicitud falló. El recurso puede volver a intentarlo después.&lt;br /&gt;
&lt;br /&gt;
=== Mapa de VRAM ===&lt;br /&gt;
&lt;br /&gt;
El espacio se administra en bloques de gráficos de 16×16. El mapa utiliza estas tablas:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt;: comienzo de cada región y marca de región reservada.&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt;: tamaño de una región libre o referencia a la entrada de la pose que la ocupa.&lt;br /&gt;
&lt;br /&gt;
Las configuraciones de espacio determinan qué partes de SP1-SP4 pueden utilizarse. El administrador distingue:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Región !! Qué puede hacer el sistema&lt;br /&gt;
|-&lt;br /&gt;
| Reservada || No utilizarla para una pose nueva. Puede pertenecer al jugador, a gráficos fijos o a otro recurso.&lt;br /&gt;
|-&lt;br /&gt;
| Libre || Colocar una pose si cabe. Si sobra espacio, dejar el resto como otra región libre.&lt;br /&gt;
|-&lt;br /&gt;
| Ocupada || Reemplazarla solo si las poses que contiene cumplen el tiempo de protección.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
También se pueden considerar regiones contiguas para reunir el espacio que necesita una pose.&lt;br /&gt;
&lt;br /&gt;
=== Elección del espacio de reemplazo ===&lt;br /&gt;
&lt;br /&gt;
# Se descartan las regiones reservadas.&lt;br /&gt;
# Se descartan las que contienen poses utilizadas hace menos de dos frames.&lt;br /&gt;
# Entre las que tienen espacio suficiente, se favorece la mayor antigüedad sin uso.&lt;br /&gt;
# Si la antigüedad es equivalente, se elige el espacio suficiente más pequeño.&lt;br /&gt;
&lt;br /&gt;
Si una región reúne varias poses, se tiene en cuenta la protección de todas ellas. No se puede sobrescribir una pose reciente solo porque la de al lado sea antigua.&lt;br /&gt;
&lt;br /&gt;
Una pose sin uso no se borra inmediatamente. Puede seguir registrada y reutilizarse sin otra carga hasta que se reemplace.&lt;br /&gt;
&lt;br /&gt;
=== Si falla el cambio de pose ===&lt;br /&gt;
&lt;br /&gt;
Las rutinas de sprites que permiten conservar la pose anterior distinguen estos casos:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Resultado !! Qué hace el sprite&lt;br /&gt;
|-&lt;br /&gt;
| La solicitud nueva se acepta || Puede utilizar la pose solicitada.&lt;br /&gt;
|-&lt;br /&gt;
| La solicitud falla, pero existe una pose anterior válida || Mantiene esa pose anterior y actualiza su tiempo de uso para protegerla. El carry puede indicar que todavía hay una pose utilizable, aunque no se haya completado el cambio.&lt;br /&gt;
|-&lt;br /&gt;
| La solicitud falla y no existe una pose anterior válida || No tiene una pose que dibujar. Debe respetar el fallo de la llamada.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Trabajo del sprite ===&lt;br /&gt;
&lt;br /&gt;
* La lógica del sprite elige cuándo moverse y cambiar de animación.&lt;br /&gt;
* La solicitud de pose comprueba o prepara sus gráficos.&lt;br /&gt;
* El dibujo utiliza la pose disponible para preparar sus piezas.&lt;br /&gt;
* La short routine mantiene la lógica correspondiente sin realizar todo el trabajo gráfico.&lt;br /&gt;
* La long routine incluye el manejo de paleta, pose y dibujo.&lt;br /&gt;
&lt;br /&gt;
== Efectos de paleta: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
El sistema conserva los colores originales para poder cambiar de efecto, combinarlo con otro o volver a la paleta sin efecto. No debe utilizar el resultado ya afectado como si fuera la paleta original.&lt;br /&gt;
&lt;br /&gt;
=== Buffers de colores ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable o buffer !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || Colores de base en formato SNES, con 2 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || Base separada en rojo, verde y azul, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || Base separada en tono, saturación y luminosidad, con 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || Resultado en formato SNES, listo para solicitar su copia a CGRAM. Corresponde al buffer de paletas del juego.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Indicadores de cada paleta ===&lt;br /&gt;
&lt;br /&gt;
Cada bit de estos indicadores corresponde a una paleta. Las variables &amp;lt;code&amp;gt;BG&amp;lt;/code&amp;gt; cubren 0-7 y las &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt; cubren 8-F.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variables !! Qué indican&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseLoaded&amp;lt;/code&amp;gt; || Si ya se preparó la base de colores en formato SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || Si está preparada la conversión de la base a RGB.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || Si está preparada la conversión de la base a HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || Si está preparado el resultado del efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estos indicadores evitan repetir conversiones y cálculos que siguen siendo válidos.&lt;br /&gt;
&lt;br /&gt;
=== Preparar una base ===&lt;br /&gt;
&lt;br /&gt;
# Se comprueba si la paleta ya tiene una base registrada.&lt;br /&gt;
# Si no la tiene, se obtienen los colores del buffer del juego. Una carga explícita, como &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, puede proporcionar esa base directamente.&lt;br /&gt;
# Se comprueba si el efecto necesita RGB o HSL.&lt;br /&gt;
# Si falta esa conversión, se prepara y se marca como disponible.&lt;br /&gt;
&lt;br /&gt;
Si solo cambia el efecto, la base puede seguir siendo válida. Si cambian los colores originales, las llamadas de carga actualizan la base e invalidan las conversiones y resultados que deben calcularse otra vez.&lt;br /&gt;
&lt;br /&gt;
=== Datos de un efecto ===&lt;br /&gt;
&lt;br /&gt;
El ID permite consultar las tablas generadas durante la instalación:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt;: cálculo que debe realizarse.&lt;br /&gt;
* &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt;: valores de los canales o dirección de la paleta de destino de una transición.&lt;br /&gt;
* &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt;: cuánto se aplica cada cambio.&lt;br /&gt;
&lt;br /&gt;
Los canales utilizan valores de 0 a 31. Los ratios van de 0 a 127: 0 conserva el origen y 127 aplica por completo el cambio elegido.&lt;br /&gt;
&lt;br /&gt;
Los cálculos se realizan fuera de NMI. NMI realiza la transferencia de los colores resultantes.&lt;br /&gt;
&lt;br /&gt;
=== Efecto global ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || Selecciona el efecto global. El valor 0 permite restaurar los colores de base.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || Selecciona las paletas 0-7 que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || Selecciona las paletas 8-F que reciben el efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || Guarda el último ID global procesado por cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || Controla la participación del color fijo y el color 0,0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para cada paleta habilitada, el administrador:&lt;br /&gt;
&lt;br /&gt;
# Comprueba si necesita actualizar el resultado del efecto.&lt;br /&gt;
# Prepara la base RGB o HSL si todavía falta.&lt;br /&gt;
# Calcula el efecto si el resultado anterior ya no sirve.&lt;br /&gt;
# Prepara los colores en formato SNES y solicita su transferencia.&lt;br /&gt;
# Confirma el ID procesado cuando la carga correspondiente se acepta.&lt;br /&gt;
&lt;br /&gt;
Si se mantiene el mismo efecto y no cambió la base, no hace falta calcularlo otra vez. Al cambiar el ID global se invalidan los resultados anteriores, no necesariamente las bases RGB y HSL.&lt;br /&gt;
&lt;br /&gt;
El ID global 0 también requiere una actualización: el sistema debe cargar de nuevo los colores de base para quitar el efecto anterior.&lt;br /&gt;
&lt;br /&gt;
=== Efecto local y concatenación ===&lt;br /&gt;
&lt;br /&gt;
Un recurso puede tener un efecto propio y recibir también el global. Por ejemplo, un sprite puede cambiar de tono y después oscurecerse junto con el nivel.&lt;br /&gt;
&lt;br /&gt;
El orden es:&lt;br /&gt;
&lt;br /&gt;
# Preparar el resultado del efecto local.&lt;br /&gt;
# Utilizarlo como base para el efecto global mediante la llamada de concatenación.&lt;br /&gt;
# Calcular el efecto global sobre esa base.&lt;br /&gt;
# Cargar el resultado combinado, sin mostrar antes la versión que solo tiene el efecto local.&lt;br /&gt;
&lt;br /&gt;
* La concatenación RGB se utiliza con efectos RGB.&lt;br /&gt;
* La concatenación HSL se utiliza con efectos HSL.&lt;br /&gt;
* Los recursos que comparten un destino de CGRAM comparten sus colores. Para mostrar dos efectos locales distintos, necesitan destinos que permitan mantener ambos resultados.&lt;br /&gt;
&lt;br /&gt;
=== Si no se acepta la transferencia ===&lt;br /&gt;
&lt;br /&gt;
* Calcular el efecto no significa que ya esté en CGRAM.&lt;br /&gt;
* Si la transferencia no se acepta, el administrador puede volver a intentar la actualización.&lt;br /&gt;
* Cuando corresponde, se mantiene el resultado anterior utilizable hasta poder sustituirlo.&lt;br /&gt;
* No se deben cargar primero los colores originales sin efecto: podrían verse así durante un frame antes del resultado correcto.&lt;br /&gt;
&lt;br /&gt;
== Cómo trabajan juntos ==&lt;br /&gt;
&lt;br /&gt;
El recorrido de un sprite dinámico reúne estas tareas:&lt;br /&gt;
&lt;br /&gt;
# Su lógica elige la pose y la versión de paleta.&lt;br /&gt;
# La asignación busca una paleta utilizable y prepara los colores si hace falta.&lt;br /&gt;
# La caché protege la pose ya cargada o prepara la carga de una nueva.&lt;br /&gt;
# El dibujo escribe los datos de sus piezas en los buffers OAM.&lt;br /&gt;
# El administrador de efectos prepara los cambios globales pendientes.&lt;br /&gt;
# NMI realiza las transferencias de gráficos y colores solicitadas.&lt;br /&gt;
&lt;br /&gt;
Compartir gráficos, compartir una paleta y compartir una rutina de dibujo son tres cosas distintas. Dynamic Xtreme puede aprovechar cada una sin obligar a que los recursos compartan también las demás.&lt;br /&gt;
&lt;br /&gt;
== Lecturas relacionadas ==&lt;br /&gt;
&lt;br /&gt;
* [[es/Dynamic_Xtreme|Artículo principal]]: funcionalidades y compatibilidad.&lt;br /&gt;
* [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_sprite_creation_guide|Creación de sprites dinámicos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_UberASM_guide|Dynamic Xtreme con UberASM]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_ASM_API|API ASM]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21371</id>
		<title>es/Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21371"/>
		<updated>2026-10-25T01:52:01Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo funciona Dynamic Xtreme, desde la preparación de los recursos al instalarlo hasta la carga y el dibujo de una pose durante el juego.&lt;br /&gt;
&lt;br /&gt;
== Qué prepara la instalación ==&lt;br /&gt;
&lt;br /&gt;
Antes de que un sprite pueda usar sus gráficos o una paleta, Dynamic Xtreme tiene que guardarlos en la ROM y preparar la información para encontrarlos. Lo mismo ocurre con cualquier otro recurso dinámico que hayas añadido.&lt;br /&gt;
&lt;br /&gt;
Para hacerlo, la herramienta lee los DynamicInfo, DrawInfo y PaletteEffect. Cada archivo aporta una parte distinta: qué recursos se van a cargar, cómo se dibujan las poses y qué cambios de color se pueden aplicar.&lt;br /&gt;
&lt;br /&gt;
Gracias a esta preparación se generan defines en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permiten utilizar los recursos y ejecutar fácilmente las rutinas necesarias.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: recursos y datos de carga ===&lt;br /&gt;
&lt;br /&gt;
Un DynamicInfo reúne los gráficos de poses, las paletas y los recursos generales que necesita un sprite u otro código. Si incluye gráficos de poses dinámicas, la herramienta los organiza para que puedan cargarse con la distribución de tiles que espera el sistema.&lt;br /&gt;
&lt;br /&gt;
Por cada pose guarda varios datos en tablas separadas. Todas mantienen el mismo orden: la entrada de una pose en una tabla corresponde a esa misma pose en las demás.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || La cantidad de datos que utiliza cada pose, en bytes. Se utiliza para comprobar si su carga cabe en el presupuesto del frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || Cuántos bloques de 16×16 hay que reservar en VRAM para la pose. No siempre coincide exactamente con los bytes que se copian, porque una pieza incompleta también puede necesitar un bloque de espacio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || La dirección de los gráficos de cada pose en ROM. Incluye el banco, de modo que el código de carga pueda encontrar su origen completo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || Dos tamaños por pose, correspondientes a los dos tramos en que pueden dividirse sus gráficos. La rutina de carga utiliza esos tamaños para repartirlos correctamente en VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || El desplazamiento en VRAM desde el comienzo del primer tramo hasta el comienzo del segundo. Permite colocar el segundo tramo donde corresponde, aunque el primero termine con una fila incompleta.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas describen todas las poses instaladas, no solo las que están en pantalla. Más adelante, la caché guarda por separado cuáles están cargadas y dónde quedaron.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si se solicita una pose que todavía no está en VRAM, el sistema consulta cuántos bytes necesita cargar, busca espacio para sus bloques y utiliza la dirección y los datos de sus tramos para preparar la carga.&lt;br /&gt;
&lt;br /&gt;
==== Tablas de paletas ====&lt;br /&gt;
&lt;br /&gt;
Las paletas declaradas en los DynamicInfo se reúnen en &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. Esta tiene dos partes:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; guarda el ID de cada paleta.&lt;br /&gt;
* &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; guarda dónde están sus colores en ROM.&lt;br /&gt;
&lt;br /&gt;
Las dos listas siguen el orden de las paletas de los DynamicInfo. El define de offset de cada DynamicInfo indica dónde comienza su lista dentro de ellas. Al elegir una versión, el sistema suma ese índice al offset y obtiene tanto el ID como la dirección de los colores elegidos.&lt;br /&gt;
&lt;br /&gt;
El ID permite reconocer y compartir una paleta; la dirección permite cargarla. No son el número de paleta de pantalla: una misma paleta instalada puede terminar, por ejemplo, en la paleta 9 o en la C según la asignación.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y defines ====&lt;br /&gt;
&lt;br /&gt;
Los archivos declarados en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; se guardan en ROM. Su dirección y la cantidad de bytes que ocupan pueden consultarse mediante los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Por ejemplo, para &amp;lt;code&amp;gt;my_resource.bin&amp;lt;/code&amp;gt; se generan:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt;: dirección del recurso en ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt;: cantidad de bytes que ocupa.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt;: ID del recurso.&lt;br /&gt;
&lt;br /&gt;
El nombre se normaliza en PascalCase: se eliminan espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: datos y rutinas de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El DrawInfo describe cómo está formada una pose: qué tiles tiene, dónde se coloca cada uno, qué tamaño utiliza y cómo cambia al voltearse.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, Dynamic Xtreme genera rutinas de dibujo optimizadas según los parámetros que utilizan los tiles. Tiene en cuenta, por ejemplo, si necesitan desplazamientos X e Y, si comparten el mismo tamaño, si utilizan propiedades comunes y si requieren volteos.&lt;br /&gt;
&lt;br /&gt;
De esta forma, la rutina realiza el trabajo que necesita ese dibujo sin añadir el manejo de opciones que no utiliza. Varias poses pueden compartirla si necesitan el mismo tratamiento; eso no significa que compartan también sus gráficos o su ID.&lt;br /&gt;
&lt;br /&gt;
La relación entre una pose y su dibujo se guarda en estas tablas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || Dónde comienzan los datos de la pose dentro de las tablas de su rutina de dibujo. Así se localizan sus tiles y desplazamientos sin recorrer las poses anteriores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || La cantidad de tiles de la pose menos uno. Una pose de cuatro tiles guarda 3; la rutina utiliza ese valor para recorrer sus piezas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || Qué rutina de dibujo utiliza cada pose. Las poses con características compatibles pueden apuntar al mismo ID de rutina.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || Las direcciones de las rutinas de dibujo. El ID de rutina permite encontrar aquí el código que debe ejecutarse.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada rutina tiene, además, las tablas que necesitan sus poses:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos !! Qué describen&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || Los números de tile que forman la pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || Las propiedades de cada pieza, como los volteos y su prioridad respecto a las capas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || La posición de cada tile respecto al punto de origen de la pose.&lt;br /&gt;
|-&lt;br /&gt;
| Tablas de desplazamientos para los volteos || Las posiciones que deben utilizarse al voltear la pose cuando necesita una distribución distinta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || El tamaño de cada tile: 8×8 o 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
No todas estas tablas tienen que aparecer en todas las rutinas. Si un dato es igual para todas las piezas o puede obtenerse de un valor común, la herramienta puede generar una rutina que lo utilice directamente.&lt;br /&gt;
&lt;br /&gt;
La optimización se hace durante la instalación. Si todos los tiles tienen el mismo tamaño, por ejemplo, la rutina puede utilizar ese valor común sin leer un tamaño distinto para cada pieza.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: datos de los efectos ===&lt;br /&gt;
&lt;br /&gt;
Un archivo PaletteEffect contiene una lista de cambios de color. La instalación les asigna IDs y guarda sus datos en &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Como en las tablas de poses, los datos de cada efecto mantienen la misma posición en las distintas listas. Los IDs de efectos comienzan en 1; el ID 0 se utiliza para indicar que no hay efecto global.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parte de la tabla !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || La cantidad de efectos instalados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || El tipo de cada efecto, por ejemplo &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Indica qué cálculo debe realizarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || Los valores de los canales que utiliza el efecto. En una transición, estos tres bytes guardan la dirección de la paleta de destino, no valores de canales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || Cuánto se aplica el cambio en cada componente. Van de 0 a 127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Si el efecto es una transición hacia otra paleta, la herramienta también prepara esa paleta. Convierte sus colores al formato RGB o HSL que necesita la transición y los guarda en ROM. Durante el juego se puede utilizar ese destino sin tener que convertirlo de nuevo en cada llamada.&lt;br /&gt;
&lt;br /&gt;
Estas paletas de transición son distintas de las paletas normales que se cargan a CGRAM: contienen tres componentes por color y se utilizan para calcular el efecto.&lt;br /&gt;
&lt;br /&gt;
=== Cómo encuentra el código los recursos instalados ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; publica los IDs, direcciones, tamaños y offsets que necesitan los recursos. Por ejemplo, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifica una pose y &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifica el primer efecto de un archivo.&lt;br /&gt;
&lt;br /&gt;
Los nombres se normalizan en PascalCase: se eliminan separadores como espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra. &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, por ejemplo, pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También se genera &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, que guarda las direcciones de los bloques donde se insertaron los recursos. La herramienta utiliza esa información para localizar los datos de una instalación anterior al reinstalar.&lt;br /&gt;
&lt;br /&gt;
Una reinstalación puede cambiar IDs y direcciones. Por eso hay que volver a insertar los sprites, bloques y códigos UberASM que utilizan los defines generados.&lt;br /&gt;
&lt;br /&gt;
== El trabajo de cada frame ==&lt;br /&gt;
&lt;br /&gt;
En la lógica principal se ejecutan el jugador, los sprites y los demás códigos del modo de juego. Los que utilizan Dynamic Xtreme solicitan las poses y paletas que necesitan, preparan los efectos locales y llaman a las rutinas de dibujo. Las cargas que se aceptan quedan anotadas para transferir sus datos durante NMI.&lt;br /&gt;
&lt;br /&gt;
Al terminar esa lógica, el código de game mode de Dynamic Xtreme realiza las tareas que correspondan a las opciones habilitadas: prepara las actualizaciones de VRAM de la optimización de Kevin, mantiene el estado de las paletas y calcula los efectos globales pendientes.&lt;br /&gt;
&lt;br /&gt;
Después, durante NMI, se ejecutan las transferencias preparadas: los gráficos se copian a VRAM y los colores a CGRAM. También se reinicia el contador de datos y se actualizan los relojes del sistema para el siguiente ciclo de trabajo.&lt;br /&gt;
&lt;br /&gt;
El orden que seguiremos para explicarlo es, por tanto, &#039;&#039;&#039;lógica principal → tareas al terminar el game mode → transferencias durante NMI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Lógica principal ===&lt;br /&gt;
&lt;br /&gt;
Cada recurso decide qué necesita. Un sprite puede cambiar de pose, una animación puede pedir nuevos gráficos y un código UberASM puede cargar una paleta o seleccionar un efecto.&lt;br /&gt;
&lt;br /&gt;
Si la pose solicitada ya está cargada, Dynamic Xtreme actualiza su tiempo de último uso para protegerla del reemplazo y no vuelve a cargar sus gráficos. Si no está cargada, comprueba el presupuesto de datos del frame y busca espacio disponible en VRAM antes de preparar su carga.&lt;br /&gt;
&lt;br /&gt;
El dibujo también se prepara en esta parte: las rutinas escriben en los buffers OAM la posición, los tiles y las propiedades de las piezas que se mostrarán.&lt;br /&gt;
&lt;br /&gt;
Una solicitud puede rechazarse, por ejemplo si no queda presupuesto para sus datos. El recurso que la pidió debe comprobar el resultado y decidir si conserva lo anterior o vuelve a intentarlo después. Una carga rechazada no queda guardada automáticamente para otro frame.&lt;br /&gt;
&lt;br /&gt;
=== Tareas de game mode ===&lt;br /&gt;
&lt;br /&gt;
En esta parte se realizan las siguientes tareas, según las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antes de ejecutar la lógica del juego:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitado &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;, se ejecuta la rutina del control aquí en lugar de hacerlo en NMI.&lt;br /&gt;
# Se comprueba si Dynamic Xtreme debe funcionar en el game mode actual. Si no debe hacerlo, se reinician sus variables. Esto ocurre cada frame que se permanezca en un modo no permitido.&lt;br /&gt;
&lt;br /&gt;
Después se ejecuta la lógica normal del juego, incluidos los sprites y los códigos que solicitan cargas o cambios de paleta.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cuando termina esa lógica:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitada la optimización de VRAM de Kevin, se ajustan los destinos de las actualizaciones de Lunar Magic antes de que se transfieran.&lt;br /&gt;
# Se ponen en 0 los indicadores de actualización de las paletas y se resta 1 a sus temporizadores de protección si todavía son mayores que 0. Esta parte se omite durante la pausa y en los modos no permitidos.&lt;br /&gt;
# Se aplican los efectos globales a las paletas que necesitan actualizarse y se preparan las transferencias de sus colores. Esta parte también se omite si la comprobación anterior impide continuar.&lt;br /&gt;
&lt;br /&gt;
Las copias a VRAM y CGRAM se realizan después, durante NMI. Aquí se deja preparado lo que se va a copiar.&lt;br /&gt;
&lt;br /&gt;
=== Transferencias durante NMI ===&lt;br /&gt;
&lt;br /&gt;
NMI es una interrupción que SNES puede generar al comenzar VBlank, después de dibujar la parte visible de la pantalla. El juego aprovecha ese intervalo para actualizar gráficos, colores y otros datos de video.&lt;br /&gt;
&lt;br /&gt;
En los modos permitidos, la rutina de Dynamic Xtreme reinicia &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; y actualiza sus relojes. Después ejecuta las transferencias de gráficos pendientes y luego las de paletas. Si corresponde, también actualiza el color 0,0 preparado por el sistema de efectos.&lt;br /&gt;
&lt;br /&gt;
Para realizar las copias se utiliza DMA. NMI lee cada carga de las listas, configura desde dónde se copiarán los datos, cuántos bytes se copiarán y dónde se colocarán, y ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
El tiempo de VBlank es limitado y SMW también lo necesita para sus actualizaciones de pantalla. Para limitar la cantidad de datos enviados en un frame y evitar flickering, Dynamic Xtreme utiliza &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, que cuenta los bytes de las cargas solicitadas, y &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, que establece el límite permitido. Antes de aceptar una carga normal, se comprueba que sus bytes no hagan superar ese límite.&lt;br /&gt;
&lt;br /&gt;
==== Las listas de transferencias ====&lt;br /&gt;
&lt;br /&gt;
Cada transferencia guarda el origen de los datos, su banco, la cantidad de bytes y el destino en VRAM o CGRAM.&lt;br /&gt;
&lt;br /&gt;
Al realizar las copias, NMI recorre las listas desde la última entrada hacia la primera y después las vacía. Esto no borra los gráficos o colores cargados: permanecen en su destino hasta que otro código los cambie.&lt;br /&gt;
&lt;br /&gt;
La lista de VRAM utiliza 0 cuando no tiene entradas. La de CGRAM utiliza &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, porque guarda el índice de la última entrada en lugar de guardar directamente su cantidad.&lt;br /&gt;
&lt;br /&gt;
Si dos códigos escriben sobre el mismo destino, deben coordinar sus cargas. El orden de las solicitudes no debe utilizarse como sustituto de decidir qué recurso puede ocupar cada espacio.&lt;br /&gt;
&lt;br /&gt;
Normalmente, el recurso se lee desde ROM. Si el recurso se encuentra en un buffer en RAM, por ejemplo una paleta cuyos colores calculaste durante el juego, conserva su contenido hasta que NMI realice la transferencia. La lista guarda la dirección del buffer, no una copia de sus datos: si los cambias antes, se enviará el contenido nuevo en lugar del que querías cargar.&lt;br /&gt;
&lt;br /&gt;
==== Presupuesto de datos ====&lt;br /&gt;
&lt;br /&gt;
Las macros de transferencia, como &amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt;, comprueban cuántos bytes se han solicitado mediante &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;. Si al añadir la nueva carga se supera &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;, la rechazan. Si la aceptan, suman sus bytes al contador.&lt;br /&gt;
&lt;br /&gt;
El límite predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Su objetivo es evitar flickering por enviar demasiados datos en un mismo frame. Es un límite de cantidad de datos, no una medida exacta del tiempo que tarda cada transferencia.&lt;br /&gt;
&lt;br /&gt;
Estas macros tienen variantes como &amp;lt;code&amp;gt;%ForcedTransferToVRAM()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ForcedTransferToCGRAM()&amp;lt;/code&amp;gt;, que aceptan la carga sin comprobar si supera el límite. Sus bytes también se suman a &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt;, por lo que reducen lo que queda disponible para las siguientes cargas normales. Se utilizan para cargas prioritarias, como las del jugador; usarlas no evita el flickering si se solicita una cantidad excesiva de datos.&lt;br /&gt;
&lt;br /&gt;
==== Los dos relojes ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_Timer: protección de las solicitudes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza cuando se ejecuta la parte de NMI de Dynamic Xtreme. Además de medir cuánto lleva una pose sin utilizarse, sirve para evitar que un recurso repita sus solicitudes antes de que se procesen las anteriores.&lt;br /&gt;
&lt;br /&gt;
No siempre hay un ciclo de lógica por cada ejecución completa de NMI. Durante slowdown, SMW puede ejecutar una versión reducida de NMI, y puede haber dos ciclos de lógica sin que entre ellos se hayan procesado las listas de transferencias de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Sin una protección, un recurso podría añadir otra vez sus cargas a esas listas. Las solicitudes repetidas ocuparían más espacio y podrían provocar flickering.&lt;br /&gt;
&lt;br /&gt;
Para evitarlo, las rutinas con esta protección comparan &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; con un valor guardado por el recurso, normalmente llamado &amp;lt;code&amp;gt;SafeFrame&amp;lt;/code&amp;gt;. Si coinciden, el recurso ya hizo su intento con ese valor del reloj y no debe añadir de nuevo las cargas. Si son distintos, guarda el valor actual y puede realizar la nueva solicitud.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; continúa avanzando durante la pausa cuando se ejecuta esa parte de NMI.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DX_SyncTimer: animaciones sincronizadas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
La función principal de &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; es dar a los sprites un reloj común para sus animaciones. Por ejemplo, varios sprites que utilizan las mismas poses pueden calcular con este reloj qué pose les corresponde cada cuatro frames.&lt;br /&gt;
&lt;br /&gt;
Así todos cambian al mismo tiempo y solicitan la misma pose. La primera solicitud puede necesitar cargarla; las demás la reutilizan sin programar otra carga de sus gráficos. Esto ahorra transferencias DMA y datos enviados por frame.&lt;br /&gt;
&lt;br /&gt;
Si cada sprite llevara un reloj independiente, podrían terminar usando poses distintas de la misma animación al mismo tiempo y necesitar más cargas y espacio de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; se detiene durante la pausa y cuando se congela la acción, para que las animaciones sincronizadas también se detengan.&lt;br /&gt;
&lt;br /&gt;
== Carga de gráficos: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; permite programar cargas de gráficos a VRAM. Lo utilizan las animaciones de tiles, las poses dinámicas y las rutinas de gráficos del jugador y Yoshi.&lt;br /&gt;
&lt;br /&gt;
La idea básica es sencilla: el código indica qué datos quiere copiar y dónde quiere ponerlos. Si la solicitud se acepta, se añade a la lista y sus bytes cuentan para el presupuesto del frame.&lt;br /&gt;
&lt;br /&gt;
Esta parte no elige la siguiente imagen de una animación ni reparte por sí sola el espacio entre sprites. Esas decisiones las toma el código que solicita la carga o el administrador de poses dinámicas.&lt;br /&gt;
&lt;br /&gt;
=== Animaciones en un destino fijo ===&lt;br /&gt;
&lt;br /&gt;
Una animación puede cambiar los gráficos de unos tiles sin cambiar sus números. Para ello copia cada imagen al mismo lugar de VRAM.&lt;br /&gt;
&lt;br /&gt;
El código de animación elige la imagen y pide su carga. Si no se acepta, puede mantener la imagen anterior y esperar al siguiente intento.&lt;br /&gt;
&lt;br /&gt;
Así la animación tiene en cuenta las demás cargas del frame en lugar de copiar sus gráficos sin importar cuánto trabajo se había pedido.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se colocan los gráficos de una pose ===&lt;br /&gt;
&lt;br /&gt;
Los gráficos de una pose pueden necesitar varias transferencias para quedar en las filas de tiles correctas. No siempre se pueden copiar como un bloque seguido a partir de una única dirección de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; utiliza los tamaños y desplazamientos preparados al instalar. Recibe el lugar elegido para la pose, calcula los destinos y añade las transferencias necesarias.&lt;br /&gt;
&lt;br /&gt;
Encontrar ese lugar y decidir si puede utilizarse es el trabajo de la caché, que se explica más adelante. La rutina de carga se ocupa de colocar los gráficos en él.&lt;br /&gt;
&lt;br /&gt;
== Carga y asignación de paletas: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
Una paleta instalada es un conjunto de colores guardados en ROM. Una paleta de pantalla es el lugar de CGRAM donde se colocan esos colores para dibujar.&lt;br /&gt;
&lt;br /&gt;
Un sprite puede pedir su paleta azul sin exigir que siempre ocupe la paleta 9. La asignación automática puede encontrarle un destino entre las paletas de sprites que tenga permitidas.&lt;br /&gt;
&lt;br /&gt;
=== Cargar colores ===&lt;br /&gt;
&lt;br /&gt;
La copia a CGRAM se prepara de forma parecida a una carga de gráficos: necesita un origen, un primer color de destino y una cantidad de bytes. Cada color de SNES ocupa dos bytes.&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; también actualizan las copias de colores del juego. Esto es importante porque SMW puede volver a utilizarlas, por ejemplo durante la animación de victoria del goal. Cambiar solo CGRAM dejaría esas copias con los colores anteriores.&lt;br /&gt;
&lt;br /&gt;
Cuando la paleta debe recibir un efecto global, se guardan primero sus colores originales. El sistema calcula el efecto sobre ellos y carga el resultado, sin mostrar antes una versión sin efecto.&lt;br /&gt;
&lt;br /&gt;
=== Encontrar una paleta disponible ===&lt;br /&gt;
&lt;br /&gt;
Para asignar un destino, el sistema busca primero una paleta con el mismo ID y una condición de efecto compatible. Si ya existe, puede compartirla en lugar de cargar otra copia.&lt;br /&gt;
&lt;br /&gt;
Si no la encuentra, busca una entrada libre. Si tampoco hay una libre, puede reemplazar una que haya dejado de estar protegida.&lt;br /&gt;
&lt;br /&gt;
Cada entrada guarda qué ID utiliza y un temporizador de protección. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; significa que está libre; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; significa que está reservada y que la asignación automática no debe ocuparla.&lt;br /&gt;
&lt;br /&gt;
Mientras un recurso utiliza su paleta, mantiene ese temporizador en 2. Así otro recurso no la reemplaza entre un frame y el siguiente.&lt;br /&gt;
&lt;br /&gt;
Cuando el temporizador llega a cero, los colores no desaparecen. Si alguien vuelve a pedir la misma paleta antes de que se reemplace, todavía puede aprovechar esa asignación.&lt;br /&gt;
&lt;br /&gt;
=== Asignación manual y versión ===&lt;br /&gt;
&lt;br /&gt;
En modo manual, el código elige el destino. Puede cargar allí sus colores o utilizar los que ya estaban preparados en el nivel. Si dos recursos eligen ese destino con colores distintos, tendrán que coordinarse para no sobrescribirse.&lt;br /&gt;
&lt;br /&gt;
En las rutinas de sprites, la versión elige una entrada de la lista de paletas del DynamicInfo. La última versión procesada permite saber si esa selección cambió.&lt;br /&gt;
&lt;br /&gt;
Mantener una paleta en uso no implica volver a cargarla cada frame. Si sigue siendo válida, lo que se mantiene es su protección.&lt;br /&gt;
&lt;br /&gt;
== Dibujo de poses: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
Tener los gráficos en VRAM no hace que un sprite aparezca por sí solo. También hay que indicar qué tiles lo forman, dónde van y con qué propiedades se muestran.&lt;br /&gt;
&lt;br /&gt;
Ese es el trabajo del dibujo. El sistema toma la pose del DrawInfo y prepara sus piezas en OAM, la memoria que utiliza la consola para colocar los sprites en pantalla.&lt;br /&gt;
&lt;br /&gt;
=== De los datos a las piezas visibles ===&lt;br /&gt;
&lt;br /&gt;
La rutina suma a la posición del sprite los desplazamientos de cada tile. También aplica los volteos y combina la paleta y las demás propiedades necesarias.&lt;br /&gt;
&lt;br /&gt;
En una pose dinámica, ajusta los tiles al lugar donde quedaron cargados sus gráficos. En una pose estática, utiliza sus posiciones fijas. Si el dibujo toma un tile común desde &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, el código debe preparar ese valor.&lt;br /&gt;
&lt;br /&gt;
Antes de añadir una pieza, se comprueba si puede verse en pantalla y si queda espacio de OAM. Tener una pose cargada no garantiza que puedan dibujarse todas sus piezas.&lt;br /&gt;
&lt;br /&gt;
=== Prioridad de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El sistema organiza las piezas según la prioridad de dibujo. En LoROM lleva su propio control de las entradas disponibles; en SA-1 utiliza la integración con MaxTile.&lt;br /&gt;
&lt;br /&gt;
Esta prioridad decide el orden entre piezas de sprites. No es lo mismo que la propiedad que determina si un tile queda delante o detrás de las capas del nivel.&lt;br /&gt;
&lt;br /&gt;
La organización de OAM ayuda a utilizar su espacio, pero no elimina el límite de sprites y tiles que SNES puede mostrar en una misma línea.&lt;br /&gt;
&lt;br /&gt;
== Jugador y Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
El jugador original tiene rutinas propias para elegir y cargar las piezas de sus poses. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; permite integrar ese trabajo con las cargas de Dynamic Xtreme y cambiar el origen de sus gráficos y paletas.&lt;br /&gt;
&lt;br /&gt;
Con el formato original, el juego sigue eligiendo las piezas de la pose. La rutina obtiene sus direcciones desde el origen configurado y compara esas direcciones con las anteriores para cargar las que hayan cambiado.&lt;br /&gt;
&lt;br /&gt;
Estas cargas utilizan transferencias forzadas y sus bytes también cuentan para las solicitudes normales posteriores. Así conservan su prioridad sin quedar fuera de la contabilidad del sistema.&lt;br /&gt;
&lt;br /&gt;
La paleta del jugador tiene un tratamiento especial: combina colores y selecciones del propio juego con el origen personalizado. No funciona simplemente como sustituir una paleta completa de un sprite cualquiera.&lt;br /&gt;
&lt;br /&gt;
El soporte para jugadores personalizados permite que otros sistemas administren de otra forma sus poses y dibujo. No convierte automáticamente cualquier spritesheet al formato del jugador original.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi también carga sus gráficos por piezas. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; permite cambiar su origen manteniendo la organización que esperan sus rutinas.&lt;br /&gt;
&lt;br /&gt;
El código calcula qué partes necesita y prepara sus cargas a los destinos correspondientes de VRAM. Como las del jugador, estas cargas tienen un tratamiento prioritario.&lt;br /&gt;
&lt;br /&gt;
Esta opción necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad. No permite evitar un conflicto del sistema del jugador habilitando únicamente las funciones de Yoshi.&lt;br /&gt;
&lt;br /&gt;
== Memoria y optimizaciones ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW mantiene en RAM gráficos originales del jugador, Yoshi y ciertas animaciones. En ROMs sin SA-1, esta opción adapta las cargas para leer esos datos desde ROM.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aprovecha la RAM recuperada para sus variables internas. No es un espacio que quede libre para que cualquier otro código escriba encima.&lt;br /&gt;
&lt;br /&gt;
SA-1 utiliza otras direcciones y desactiva esta opción. Los rangos están en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
Esta opción mueve el procesamiento del control desde NMI a la parte de game mode. El objetivo es dejar más tiempo para las actualizaciones de pantalla, no añadir un frame de retraso ni cambiar los botones que recibe el juego.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
El color fijo se utiliza en las mezclas de color de la consola. Para actualizarlo, el juego prepara sus componentes y los envía al registro correspondiente.&lt;br /&gt;
&lt;br /&gt;
La optimización reemplaza esa preparación por una secuencia más corta. El color sigue enviándose a la consola, pero necesita menos trabajo durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic utiliza listas llamadas stripe images para actualizar partes de los mapas de tiles. Esas listas incluyen tanto los datos como la información sobre sus destinos.&lt;br /&gt;
&lt;br /&gt;
La versión integrada de la optimización de Kevin prepara fuera de NMI parte del ajuste de esos destinos. Así deja menos trabajo de preparación para el momento de la transferencia.&lt;br /&gt;
&lt;br /&gt;
Esta opción sustituye el uso del parche original por separado. Además, no debe desinstalarse después de instalarla; hay que tenerlo en cuenta antes de activarla.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
La barra de estado original actualiza zonas concretas de VRAM. Esta opción prepara sus transferencias de forma más directa, reduciendo la configuración de DMA que necesita hacer durante NMI.&lt;br /&gt;
&lt;br /&gt;
No añade una barra nueva. Modifica la actualización de la original y, por eso, entra en conflicto con recursos que la reemplazan, modifican o eliminan.&lt;br /&gt;
&lt;br /&gt;
== Sprites dinámicos: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
El sistema utiliza el espacio disponible de VRAM como una caché de poses. Conserva las que ya cargó para reutilizarlas y busca cuáles puede reemplazar cuando hace falta espacio.&lt;br /&gt;
&lt;br /&gt;
En lugar de darle a cada sprite un espacio fijo para todos sus gráficos, permite que pida la pose que necesita en ese momento.&lt;br /&gt;
&lt;br /&gt;
=== Una pose para varias entidades ===&lt;br /&gt;
&lt;br /&gt;
Si cinco sprites piden la misma pose, no hacen falta cinco copias de sus gráficos. La primera solicitud puede cargarla y las siguientes encuentran esa misma pose registrada. Después cada sprite la dibuja en su propia posición.&lt;br /&gt;
&lt;br /&gt;
La búsqueda utiliza el ID de la pose. Dos recursos con gráficos visualmente iguales no se consideran necesariamente la misma pose si tienen IDs distintos.&lt;br /&gt;
&lt;br /&gt;
=== Encontrar una pose que ya está cargada ===&lt;br /&gt;
&lt;br /&gt;
El sistema guarda el ID de cada pose registrada, su lugar en VRAM y el momento en que se utilizó por última vez.&lt;br /&gt;
&lt;br /&gt;
Para encontrarla utiliza una tabla hash de 128 entradas. Esto significa que el ID permite calcular dónde comenzar la búsqueda, en lugar de recorrer siempre todas las poses. Después se compara el ID completo para confirmar que es la correcta.&lt;br /&gt;
&lt;br /&gt;
Si la encuentra, guarda el valor actual de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; en su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt;. Así queda marcada como utilizada en este frame y no puede ser reemplazada hasta cumplir el tiempo mínimo de protección. No se programa otra transferencia de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
=== Cuando la pose todavía no está ===&lt;br /&gt;
&lt;br /&gt;
Para una pose nueva, el sistema consulta las tablas generadas desde el DynamicInfo:&lt;br /&gt;
&lt;br /&gt;
# Obtiene el tamaño de sus gráficos y comprueba el presupuesto del frame.&lt;br /&gt;
# Busca espacio para los bloques de VRAM que necesita.&lt;br /&gt;
# Retira las referencias de las poses que tenga que reemplazar.&lt;br /&gt;
# Registra la nueva pose y el lugar elegido.&lt;br /&gt;
# Prepara las transferencias de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
Si no hay presupuesto o no encuentra espacio adecuado, la solicitud falla. El código que pidió la pose puede intentarlo después.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se reparte VRAM ===&lt;br /&gt;
&lt;br /&gt;
El mapa de espacio distingue zonas reservadas, regiones libres y regiones ocupadas por poses. La reserva se mide en bloques de gráficos de 16×16.&lt;br /&gt;
&lt;br /&gt;
Las configuraciones de espacio deciden qué partes de SP1-SP4 pueden utilizarse. Una región reservada para el jugador, gráficos fijos u otro sistema no puede elegirse para una pose nueva.&lt;br /&gt;
&lt;br /&gt;
El mapa guarda dónde comienza cada región y cuánto ocupa. Puede dividir un espacio libre grande para colocar una pose y dejar el resto disponible. También puede considerar regiones contiguas para reunir el espacio necesario.&lt;br /&gt;
&lt;br /&gt;
=== Qué poses se pueden reemplazar ===&lt;br /&gt;
&lt;br /&gt;
Que una pose no se solicite en un frame no significa que deba sobrescribirse inmediatamente. El sistema protege las utilizadas recientemente y exige al menos dos frames de antigüedad para considerar su espacio.&lt;br /&gt;
&lt;br /&gt;
Entre los espacios que puede utilizar, favorece los que llevan más tiempo sin uso. Si la antigüedad es equivalente, prefiere el espacio suficiente más pequeño, dejando las regiones mayores para otras poses.&lt;br /&gt;
&lt;br /&gt;
Cuando una región reúne varias poses, la protección de todas ellas cuenta. No se puede reemplazar una parte que todavía esté protegida solo porque la pose de al lado sea antigua.&lt;br /&gt;
&lt;br /&gt;
Una pose que dejó de utilizarse puede quedarse en VRAM y continuar registrada. Si vuelve a solicitarse antes de ser reemplazada, se reutiliza sin otra carga.&lt;br /&gt;
&lt;br /&gt;
=== Conservar la pose anterior ===&lt;br /&gt;
&lt;br /&gt;
Si no se puede cargar una pose nueva, las rutinas de sprites pueden seguir utilizando una pose anterior válida. También mantienen su protección para que no se sobrescriba mientras se sigue dibujando.&lt;br /&gt;
&lt;br /&gt;
Esto explica una diferencia importante: una llamada puede devolver una pose utilizable sin haber conseguido todavía la pose nueva.&lt;br /&gt;
&lt;br /&gt;
Si el sprite nunca tuvo una pose válida, no hay una anterior que mostrar. Su código debe comprobar el resultado antes de dibujar.&lt;br /&gt;
&lt;br /&gt;
=== La lógica sigue siendo del sprite ===&lt;br /&gt;
&lt;br /&gt;
La caché no decide cuándo camina, salta o cambia de animación un personaje. El sprite elige la pose, solicita sus gráficos y dibuja con el resultado disponible.&lt;br /&gt;
&lt;br /&gt;
La separación entre short routine y long routine permite evitar parte del trabajo gráfico cuando el sprite no necesita dibujarse. La short routine conserva la lógica correspondiente; la long routine incluye el manejo de paleta, pose y dibujo.&lt;br /&gt;
&lt;br /&gt;
== Efectos de paleta: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
Para cambiar un efecto sin estropear los colores, el sistema tiene que conservar una base. Si cada cambio se aplicara sobre el resultado ya afectado del frame anterior, el color podría ir acumulando modificaciones que no se buscaban.&lt;br /&gt;
&lt;br /&gt;
Por eso se distinguen los colores originales, las versiones preparadas para el cálculo y el resultado que se va a mostrar.&lt;br /&gt;
&lt;br /&gt;
=== Conservar los colores originales ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; guarda la base en formato de SNES. A partir de ella se preparan las representaciones RGB o HSL cuando hacen falta.&lt;br /&gt;
&lt;br /&gt;
RGB separa rojo, verde y azul. HSL separa tono, saturación y luminosidad. Ambas utilizan tres bytes por color; los colores de SNES utilizan dos.&lt;br /&gt;
&lt;br /&gt;
El resultado convertido de nuevo al formato de SNES se guarda en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;, que corresponde al buffer de paletas del juego.&lt;br /&gt;
&lt;br /&gt;
El sistema lleva indicadores para saber qué bases ya tiene preparadas. Si se pasa de un efecto RGB a uno HSL, no debe tomar los colores afectados como si fueran los originales.&lt;br /&gt;
&lt;br /&gt;
=== Preparar la base cuando hace falta ===&lt;br /&gt;
&lt;br /&gt;
Una paleta sin base registrada puede obtener sus colores del buffer del juego. Una carga explícita, como &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, proporciona los colores que deben utilizarse como base.&lt;br /&gt;
&lt;br /&gt;
La conversión a RGB o HSL se hace cuando se necesita. Después puede reutilizarse mientras no cambien los colores de origen.&lt;br /&gt;
&lt;br /&gt;
Cuando llegan colores nuevos, las conversiones y efectos anteriores dejan de servir. Las llamadas correspondientes de carga actualizan la base y borran los indicadores que deben volver a calcularse.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto ===&lt;br /&gt;
&lt;br /&gt;
El ID del efecto permite leer su tipo, valores y ratios en las tablas preparadas al instalar.&lt;br /&gt;
&lt;br /&gt;
Los canales utilizan valores de 0 a 31. Los ratios van de 0 a 127: 0 conserva el origen y 127 aplica por completo el cambio elegido.&lt;br /&gt;
&lt;br /&gt;
Un efecto puede modificar un canal, varios canales o mezclar los colores con los de otra paleta. Las transiciones utilizan los destinos RGB o HSL que ya se prepararon durante la instalación.&lt;br /&gt;
&lt;br /&gt;
Los cálculos se hacen fuera de NMI. La parte de NMI se encarga de copiar los colores resultantes, no de calcular cada efecto durante la transferencia.&lt;br /&gt;
&lt;br /&gt;
=== El efecto global ===&lt;br /&gt;
&lt;br /&gt;
El juego selecciona un ID global y elige mediante máscaras qué paletas deben recibirlo. El color fijo y el color 0,0 tienen sus propios indicadores.&lt;br /&gt;
&lt;br /&gt;
El administrador comprueba si cada paleta necesita una actualización. Si la base no cambió y sigue siendo válido el resultado del mismo efecto, puede reutilizarlo.&lt;br /&gt;
&lt;br /&gt;
Al cambiar el ID global, los resultados del efecto anterior dejan de servir, pero las bases RGB y HSL pueden seguir siendo válidas si sus colores de origen no cambiaron.&lt;br /&gt;
&lt;br /&gt;
Poner el ID global en 0 permite volver a los colores de base. Para restaurarlos, el sistema todavía tiene que procesar las paletas afectadas; no basta con dejar de trabajar sobre ellas.&lt;br /&gt;
&lt;br /&gt;
=== Combinar un efecto local con el global ===&lt;br /&gt;
&lt;br /&gt;
Un sprite puede necesitar un cambio de color propio y, además, recibir el efecto general del nivel. Por ejemplo, puede cambiar de tono y después oscurecerse junto con el resto de la pantalla.&lt;br /&gt;
&lt;br /&gt;
Las llamadas de concatenación permiten preparar el resultado local como base del efecto global. La variante RGB se utiliza con efectos RGB; la HSL, con efectos HSL.&lt;br /&gt;
&lt;br /&gt;
No hay que mostrar primero el resultado local sin el efecto global. Se prepara la base para que la carga final ya contenga la combinación correspondiente.&lt;br /&gt;
&lt;br /&gt;
Los recursos que comparten una paleta de CGRAM también comparten sus colores. Dos sprites que necesiten efectos locales diferentes deben disponer de destinos adecuados para mostrar ambos resultados.&lt;br /&gt;
&lt;br /&gt;
=== Cargar el resultado ===&lt;br /&gt;
&lt;br /&gt;
Cuando los colores están preparados, se solicita su transferencia a CGRAM. Esa carga también puede quedar pendiente si no se acepta por el presupuesto.&lt;br /&gt;
&lt;br /&gt;
Preparar una base o calcular un efecto no significa que ya esté en pantalla. El administrador confirma sus cambios de estado según el resultado de la carga y puede volver a intentar una actualización pendiente.&lt;br /&gt;
&lt;br /&gt;
Cuando corresponde, se mantiene un resultado anterior utilizable hasta poder sustituirlo. Esto permite distinguir una paleta que todavía está cambiando de una que nunca tuvo colores disponibles para mostrarse.&lt;br /&gt;
&lt;br /&gt;
Cargar directamente los colores originales antes del efecto podría hacer que se vieran un frame sin él. Por eso las cargas destinadas al efecto global preparan la base y dejan que se muestre el resultado ya procesado.&lt;br /&gt;
&lt;br /&gt;
== Cómo trabajan juntos ==&lt;br /&gt;
&lt;br /&gt;
Un sprite dinámico utiliza varias de estas partes durante el mismo frame. Su lógica elige una pose y una paleta; la asignación encuentra colores utilizables; la caché encuentra o prepara los gráficos; y el dibujo coloca sus piezas.&lt;br /&gt;
&lt;br /&gt;
Después, el administrador de efectos prepara los cambios globales que hagan falta y NMI realiza las transferencias solicitadas.&lt;br /&gt;
&lt;br /&gt;
Compartir gráficos, compartir una paleta y compartir una rutina de dibujo son tres cosas distintas. Dynamic Xtreme puede aprovechar cada una sin obligar a que los recursos compartan también las demás.&lt;br /&gt;
&lt;br /&gt;
== Lecturas relacionadas ==&lt;br /&gt;
&lt;br /&gt;
* [[es/Dynamic_Xtreme|Artículo principal]]: funcionalidades y compatibilidad.&lt;br /&gt;
* [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_sprite_creation_guide|Creación de sprites dinámicos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_UberASM_guide|Dynamic Xtreme con UberASM]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_ASM_API|API ASM]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21370</id>
		<title>es/Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21370"/>
		<updated>2026-10-25T01:39:13Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo funciona Dynamic Xtreme, desde la preparación de los recursos al instalarlo hasta la carga y el dibujo de una pose durante el juego.&lt;br /&gt;
&lt;br /&gt;
== Qué prepara la instalación ==&lt;br /&gt;
&lt;br /&gt;
Antes de que un sprite pueda usar sus gráficos o una paleta, Dynamic Xtreme tiene que guardarlos en la ROM y preparar la información para encontrarlos. Lo mismo ocurre con cualquier otro recurso dinámico que hayas añadido.&lt;br /&gt;
&lt;br /&gt;
Para hacerlo, la herramienta lee los DynamicInfo, DrawInfo y PaletteEffect. Cada archivo aporta una parte distinta: qué recursos se van a cargar, cómo se dibujan las poses y qué cambios de color se pueden aplicar.&lt;br /&gt;
&lt;br /&gt;
Gracias a esta preparación se generan defines en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permiten utilizar los recursos y ejecutar fácilmente las rutinas necesarias.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: recursos y datos de carga ===&lt;br /&gt;
&lt;br /&gt;
Un DynamicInfo reúne los gráficos de poses, las paletas y los recursos generales que necesita un sprite u otro código. Si incluye gráficos de poses dinámicas, la herramienta los organiza para que puedan cargarse con la distribución de tiles que espera el sistema.&lt;br /&gt;
&lt;br /&gt;
Por cada pose guarda varios datos en tablas separadas. Todas mantienen el mismo orden: la entrada de una pose en una tabla corresponde a esa misma pose en las demás.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || La cantidad de datos que utiliza cada pose, en bytes. Se utiliza para comprobar si su carga cabe en el presupuesto del frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || Cuántos bloques de 16×16 hay que reservar en VRAM para la pose. No siempre coincide exactamente con los bytes que se copian, porque una pieza incompleta también puede necesitar un bloque de espacio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || La dirección de los gráficos de cada pose en ROM. Incluye el banco, de modo que el código de carga pueda encontrar su origen completo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || Dos tamaños por pose, correspondientes a los dos tramos en que pueden dividirse sus gráficos. La rutina de carga utiliza esos tamaños para repartirlos correctamente en VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || El desplazamiento en VRAM desde el comienzo del primer tramo hasta el comienzo del segundo. Permite colocar el segundo tramo donde corresponde, aunque el primero termine con una fila incompleta.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas describen todas las poses instaladas, no solo las que están en pantalla. Más adelante, la caché guarda por separado cuáles están cargadas y dónde quedaron.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si se solicita una pose que todavía no está en VRAM, el sistema consulta cuántos bytes necesita cargar, busca espacio para sus bloques y utiliza la dirección y los datos de sus tramos para preparar la carga.&lt;br /&gt;
&lt;br /&gt;
==== Tablas de paletas ====&lt;br /&gt;
&lt;br /&gt;
Las paletas declaradas en los DynamicInfo se reúnen en &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. Esta tiene dos partes:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; guarda el ID de cada paleta.&lt;br /&gt;
* &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; guarda dónde están sus colores en ROM.&lt;br /&gt;
&lt;br /&gt;
Las dos listas siguen el orden de las paletas de los DynamicInfo. El define de offset de cada DynamicInfo indica dónde comienza su lista dentro de ellas. Al elegir una versión, el sistema suma ese índice al offset y obtiene tanto el ID como la dirección de los colores elegidos.&lt;br /&gt;
&lt;br /&gt;
El ID permite reconocer y compartir una paleta; la dirección permite cargarla. No son el número de paleta de pantalla: una misma paleta instalada puede terminar, por ejemplo, en la paleta 9 o en la C según la asignación.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y defines ====&lt;br /&gt;
&lt;br /&gt;
Los archivos declarados en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; se guardan en ROM. Su dirección y la cantidad de bytes que ocupan pueden consultarse mediante los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Por ejemplo, para &amp;lt;code&amp;gt;my_resource.bin&amp;lt;/code&amp;gt; se generan:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt;: dirección del recurso en ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt;: cantidad de bytes que ocupa.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt;: ID del recurso.&lt;br /&gt;
&lt;br /&gt;
El nombre se normaliza en PascalCase: se eliminan espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: datos y rutinas de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El DrawInfo describe cómo está formada una pose: qué tiles tiene, dónde se coloca cada uno, qué tamaño utiliza y cómo cambia al voltearse.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, Dynamic Xtreme genera rutinas de dibujo optimizadas según los parámetros que utilizan los tiles. Tiene en cuenta, por ejemplo, si necesitan desplazamientos X e Y, si comparten el mismo tamaño, si utilizan propiedades comunes y si requieren volteos.&lt;br /&gt;
&lt;br /&gt;
De esta forma, la rutina realiza el trabajo que necesita ese dibujo sin añadir el manejo de opciones que no utiliza. Varias poses pueden compartirla si necesitan el mismo tratamiento; eso no significa que compartan también sus gráficos o su ID.&lt;br /&gt;
&lt;br /&gt;
La relación entre una pose y su dibujo se guarda en estas tablas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || Dónde comienzan los datos de la pose dentro de las tablas de su rutina de dibujo. Así se localizan sus tiles y desplazamientos sin recorrer las poses anteriores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || La cantidad de tiles de la pose menos uno. Una pose de cuatro tiles guarda 3; la rutina utiliza ese valor para recorrer sus piezas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || Qué rutina de dibujo utiliza cada pose. Las poses con características compatibles pueden apuntar al mismo ID de rutina.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || Las direcciones de las rutinas de dibujo. El ID de rutina permite encontrar aquí el código que debe ejecutarse.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada rutina tiene, además, las tablas que necesitan sus poses:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos !! Qué describen&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || Los números de tile que forman la pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || Las propiedades de cada pieza, como los volteos y su prioridad respecto a las capas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || La posición de cada tile respecto al punto de origen de la pose.&lt;br /&gt;
|-&lt;br /&gt;
| Tablas de desplazamientos para los volteos || Las posiciones que deben utilizarse al voltear la pose cuando necesita una distribución distinta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || El tamaño de cada tile: 8×8 o 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
No todas estas tablas tienen que aparecer en todas las rutinas. Si un dato es igual para todas las piezas o puede obtenerse de un valor común, la herramienta puede generar una rutina que lo utilice directamente.&lt;br /&gt;
&lt;br /&gt;
La optimización se hace durante la instalación. Si todos los tiles tienen el mismo tamaño, por ejemplo, la rutina puede utilizar ese valor común sin leer un tamaño distinto para cada pieza.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: datos de los efectos ===&lt;br /&gt;
&lt;br /&gt;
Un archivo PaletteEffect contiene una lista de cambios de color. La instalación les asigna IDs y guarda sus datos en &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Como en las tablas de poses, los datos de cada efecto mantienen la misma posición en las distintas listas. Los IDs de efectos comienzan en 1; el ID 0 se utiliza para indicar que no hay efecto global.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parte de la tabla !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || La cantidad de efectos instalados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || El tipo de cada efecto, por ejemplo &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Indica qué cálculo debe realizarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || Los valores de los canales que utiliza el efecto. En una transición, estos tres bytes guardan la dirección de la paleta de destino, no valores de canales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || Cuánto se aplica el cambio en cada componente. Van de 0 a 127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Si el efecto es una transición hacia otra paleta, la herramienta también prepara esa paleta. Convierte sus colores al formato RGB o HSL que necesita la transición y los guarda en ROM. Durante el juego se puede utilizar ese destino sin tener que convertirlo de nuevo en cada llamada.&lt;br /&gt;
&lt;br /&gt;
Estas paletas de transición son distintas de las paletas normales que se cargan a CGRAM: contienen tres componentes por color y se utilizan para calcular el efecto.&lt;br /&gt;
&lt;br /&gt;
=== Cómo encuentra el código los recursos instalados ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; publica los IDs, direcciones, tamaños y offsets que necesitan los recursos. Por ejemplo, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifica una pose y &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifica el primer efecto de un archivo.&lt;br /&gt;
&lt;br /&gt;
Los nombres se normalizan en PascalCase: se eliminan separadores como espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra. &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, por ejemplo, pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También se genera &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, que guarda las direcciones de los bloques donde se insertaron los recursos. La herramienta utiliza esa información para localizar los datos de una instalación anterior al reinstalar.&lt;br /&gt;
&lt;br /&gt;
Una reinstalación puede cambiar IDs y direcciones. Por eso hay que volver a insertar los sprites, bloques y códigos UberASM que utilizan los defines generados.&lt;br /&gt;
&lt;br /&gt;
== El trabajo de cada frame ==&lt;br /&gt;
&lt;br /&gt;
En la lógica principal se ejecutan el jugador, los sprites y los demás códigos del modo de juego. Los que utilizan Dynamic Xtreme solicitan las poses y paletas que necesitan, preparan los efectos locales y llaman a las rutinas de dibujo. Las cargas que se aceptan quedan anotadas para transferir sus datos durante NMI.&lt;br /&gt;
&lt;br /&gt;
Al terminar esa lógica, el código de game mode de Dynamic Xtreme realiza las tareas que correspondan a las opciones habilitadas: prepara las actualizaciones de VRAM de la optimización de Kevin, mantiene el estado de las paletas y calcula los efectos globales pendientes.&lt;br /&gt;
&lt;br /&gt;
Después, durante NMI, se ejecutan las transferencias preparadas: los gráficos se copian a VRAM y los colores a CGRAM. También se reinicia el contador de datos y se actualizan los relojes del sistema para el siguiente ciclo de trabajo.&lt;br /&gt;
&lt;br /&gt;
El orden que seguiremos para explicarlo es, por tanto, &#039;&#039;&#039;lógica principal → tareas al terminar el game mode → transferencias durante NMI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Lógica principal ===&lt;br /&gt;
&lt;br /&gt;
Cada recurso decide qué necesita. Un sprite puede cambiar de pose, una animación puede pedir nuevos gráficos y un código UberASM puede cargar una paleta o seleccionar un efecto.&lt;br /&gt;
&lt;br /&gt;
Si la pose solicitada ya está cargada, Dynamic Xtreme actualiza su tiempo de último uso para protegerla del reemplazo y no vuelve a cargar sus gráficos. Si no está cargada, comprueba el presupuesto de datos del frame y busca espacio disponible en VRAM antes de preparar su carga.&lt;br /&gt;
&lt;br /&gt;
El dibujo también se prepara en esta parte: las rutinas escriben en los buffers OAM la posición, los tiles y las propiedades de las piezas que se mostrarán.&lt;br /&gt;
&lt;br /&gt;
Una solicitud puede rechazarse, por ejemplo si no queda presupuesto para sus datos. El recurso que la pidió debe comprobar el resultado y decidir si conserva lo anterior o vuelve a intentarlo después. Una carga rechazada no queda guardada automáticamente para otro frame.&lt;br /&gt;
&lt;br /&gt;
=== Tareas de game mode ===&lt;br /&gt;
&lt;br /&gt;
En esta parte se realizan las siguientes tareas, según las funcionalidades habilitadas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antes de ejecutar la lógica del juego:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitado &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;, se ejecuta la rutina del control aquí en lugar de hacerlo en NMI.&lt;br /&gt;
# Se comprueba si Dynamic Xtreme debe funcionar en el game mode actual. Si no debe hacerlo, se reinician sus variables. Esto ocurre cada frame que se permanezca en un modo no permitido.&lt;br /&gt;
&lt;br /&gt;
Después se ejecuta la lógica normal del juego, incluidos los sprites y los códigos que solicitan cargas o cambios de paleta.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cuando termina esa lógica:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Si está habilitada la optimización de VRAM de Kevin, se ajustan los destinos de las actualizaciones de Lunar Magic antes de que se transfieran.&lt;br /&gt;
# Se ponen en 0 los indicadores de actualización de las paletas y se resta 1 a sus temporizadores de protección si todavía son mayores que 0. Esta parte se omite durante la pausa y en los modos no permitidos.&lt;br /&gt;
# Se aplican los efectos globales a las paletas que necesitan actualizarse y se preparan las transferencias de sus colores. Esta parte también se omite si la comprobación anterior impide continuar.&lt;br /&gt;
&lt;br /&gt;
Las copias a VRAM y CGRAM se realizan después, durante NMI. Aquí se deja preparado lo que se va a copiar.&lt;br /&gt;
&lt;br /&gt;
=== Transferencias durante NMI ===&lt;br /&gt;
&lt;br /&gt;
NMI es una interrupción que SNES puede generar al comenzar VBlank, después de dibujar la parte visible de la pantalla. El juego aprovecha ese intervalo para actualizar gráficos, colores y otros datos de video.&lt;br /&gt;
&lt;br /&gt;
En los modos permitidos, la rutina de Dynamic Xtreme reinicia &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; y actualiza sus relojes. Después ejecuta las transferencias de gráficos pendientes y luego las de paletas. Si corresponde, también actualiza el color 0,0 preparado por el sistema de efectos.&lt;br /&gt;
&lt;br /&gt;
Las copias utilizan DMA, el mecanismo de la consola para transferir los datos. Los cálculos de poses y efectos ya se hicieron antes; durante esta parte se utilizan los orígenes, destinos y cantidades que quedaron preparados.&lt;br /&gt;
&lt;br /&gt;
El tiempo de VBlank es limitado y también lo utilizan las tareas normales de pantalla de SMW. Por eso es importante controlar cuántos datos se solicitan y evitar trabajo innecesario dentro de NMI.&lt;br /&gt;
&lt;br /&gt;
==== Las listas de transferencias ====&lt;br /&gt;
&lt;br /&gt;
Cada transferencia guarda el origen de los datos, su banco, la cantidad de bytes y el destino en VRAM o CGRAM.&lt;br /&gt;
&lt;br /&gt;
Al realizar las copias, NMI recorre las listas desde la última entrada hacia la primera y después las vacía. Esto no borra los gráficos o colores cargados: permanecen en su destino hasta que otro código los cambie.&lt;br /&gt;
&lt;br /&gt;
La lista de VRAM utiliza 0 cuando no tiene entradas. La de CGRAM utiliza &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, porque guarda el índice de la última entrada en lugar de guardar directamente su cantidad.&lt;br /&gt;
&lt;br /&gt;
Si dos códigos escriben sobre el mismo destino, deben coordinar sus cargas. El orden de las solicitudes no debe utilizarse como sustituto de decidir qué recurso puede ocupar cada espacio.&lt;br /&gt;
&lt;br /&gt;
Cuando el origen está en RAM, los datos deben conservarse hasta que se ejecute la transferencia. Cambiarlos antes puede hacer que se copie algo distinto de lo solicitado.&lt;br /&gt;
&lt;br /&gt;
==== Presupuesto de datos ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; suma los bytes comprometidos por las cargas del sistema. Las solicitudes normales lo comparan con &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; antes de aceptarse.&lt;br /&gt;
&lt;br /&gt;
El límite predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Controla la cantidad de datos solicitados, pero no representa una medida exacta del tiempo que tardará cualquier combinación de transferencias.&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; omiten esa comprobación y también suman sus bytes al contador. Permiten dar prioridad a ciertas cargas; no aumentan el tiempo disponible de la consola.&lt;br /&gt;
&lt;br /&gt;
==== Los dos relojes ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza cada vez que se ejecuta la rutina correspondiente de Dynamic Xtreme en un modo permitido. Sigue contando durante la pausa y permite saber cuánto lleva una pose sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; se detiene durante la pausa y cuando se congela la acción. Puede utilizarse para animaciones que deban detenerse junto con el juego.&lt;br /&gt;
&lt;br /&gt;
== Carga de gráficos: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; permite programar cargas de gráficos a VRAM. Lo utilizan las animaciones de tiles, las poses dinámicas y las rutinas de gráficos del jugador y Yoshi.&lt;br /&gt;
&lt;br /&gt;
La idea básica es sencilla: el código indica qué datos quiere copiar y dónde quiere ponerlos. Si la solicitud se acepta, se añade a la lista y sus bytes cuentan para el presupuesto del frame.&lt;br /&gt;
&lt;br /&gt;
Esta parte no elige la siguiente imagen de una animación ni reparte por sí sola el espacio entre sprites. Esas decisiones las toma el código que solicita la carga o el administrador de poses dinámicas.&lt;br /&gt;
&lt;br /&gt;
=== Animaciones en un destino fijo ===&lt;br /&gt;
&lt;br /&gt;
Una animación puede cambiar los gráficos de unos tiles sin cambiar sus números. Para ello copia cada imagen al mismo lugar de VRAM.&lt;br /&gt;
&lt;br /&gt;
El código de animación elige la imagen y pide su carga. Si no se acepta, puede mantener la imagen anterior y esperar al siguiente intento.&lt;br /&gt;
&lt;br /&gt;
Así la animación tiene en cuenta las demás cargas del frame en lugar de copiar sus gráficos sin importar cuánto trabajo se había pedido.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se colocan los gráficos de una pose ===&lt;br /&gt;
&lt;br /&gt;
Los gráficos de una pose pueden necesitar varias transferencias para quedar en las filas de tiles correctas. No siempre se pueden copiar como un bloque seguido a partir de una única dirección de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; utiliza los tamaños y desplazamientos preparados al instalar. Recibe el lugar elegido para la pose, calcula los destinos y añade las transferencias necesarias.&lt;br /&gt;
&lt;br /&gt;
Encontrar ese lugar y decidir si puede utilizarse es el trabajo de la caché, que se explica más adelante. La rutina de carga se ocupa de colocar los gráficos en él.&lt;br /&gt;
&lt;br /&gt;
== Carga y asignación de paletas: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
Una paleta instalada es un conjunto de colores guardados en ROM. Una paleta de pantalla es el lugar de CGRAM donde se colocan esos colores para dibujar.&lt;br /&gt;
&lt;br /&gt;
Un sprite puede pedir su paleta azul sin exigir que siempre ocupe la paleta 9. La asignación automática puede encontrarle un destino entre las paletas de sprites que tenga permitidas.&lt;br /&gt;
&lt;br /&gt;
=== Cargar colores ===&lt;br /&gt;
&lt;br /&gt;
La copia a CGRAM se prepara de forma parecida a una carga de gráficos: necesita un origen, un primer color de destino y una cantidad de bytes. Cada color de SNES ocupa dos bytes.&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; también actualizan las copias de colores del juego. Esto es importante porque SMW puede volver a utilizarlas, por ejemplo durante la animación de victoria del goal. Cambiar solo CGRAM dejaría esas copias con los colores anteriores.&lt;br /&gt;
&lt;br /&gt;
Cuando la paleta debe recibir un efecto global, se guardan primero sus colores originales. El sistema calcula el efecto sobre ellos y carga el resultado, sin mostrar antes una versión sin efecto.&lt;br /&gt;
&lt;br /&gt;
=== Encontrar una paleta disponible ===&lt;br /&gt;
&lt;br /&gt;
Para asignar un destino, el sistema busca primero una paleta con el mismo ID y una condición de efecto compatible. Si ya existe, puede compartirla en lugar de cargar otra copia.&lt;br /&gt;
&lt;br /&gt;
Si no la encuentra, busca una entrada libre. Si tampoco hay una libre, puede reemplazar una que haya dejado de estar protegida.&lt;br /&gt;
&lt;br /&gt;
Cada entrada guarda qué ID utiliza y un temporizador de protección. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; significa que está libre; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; significa que está reservada y que la asignación automática no debe ocuparla.&lt;br /&gt;
&lt;br /&gt;
Mientras un recurso utiliza su paleta, mantiene ese temporizador en 2. Así otro recurso no la reemplaza entre un frame y el siguiente.&lt;br /&gt;
&lt;br /&gt;
Cuando el temporizador llega a cero, los colores no desaparecen. Si alguien vuelve a pedir la misma paleta antes de que se reemplace, todavía puede aprovechar esa asignación.&lt;br /&gt;
&lt;br /&gt;
=== Asignación manual y versión ===&lt;br /&gt;
&lt;br /&gt;
En modo manual, el código elige el destino. Puede cargar allí sus colores o utilizar los que ya estaban preparados en el nivel. Si dos recursos eligen ese destino con colores distintos, tendrán que coordinarse para no sobrescribirse.&lt;br /&gt;
&lt;br /&gt;
En las rutinas de sprites, la versión elige una entrada de la lista de paletas del DynamicInfo. La última versión procesada permite saber si esa selección cambió.&lt;br /&gt;
&lt;br /&gt;
Mantener una paleta en uso no implica volver a cargarla cada frame. Si sigue siendo válida, lo que se mantiene es su protección.&lt;br /&gt;
&lt;br /&gt;
== Dibujo de poses: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
Tener los gráficos en VRAM no hace que un sprite aparezca por sí solo. También hay que indicar qué tiles lo forman, dónde van y con qué propiedades se muestran.&lt;br /&gt;
&lt;br /&gt;
Ese es el trabajo del dibujo. El sistema toma la pose del DrawInfo y prepara sus piezas en OAM, la memoria que utiliza la consola para colocar los sprites en pantalla.&lt;br /&gt;
&lt;br /&gt;
=== De los datos a las piezas visibles ===&lt;br /&gt;
&lt;br /&gt;
La rutina suma a la posición del sprite los desplazamientos de cada tile. También aplica los volteos y combina la paleta y las demás propiedades necesarias.&lt;br /&gt;
&lt;br /&gt;
En una pose dinámica, ajusta los tiles al lugar donde quedaron cargados sus gráficos. En una pose estática, utiliza sus posiciones fijas. Si el dibujo toma un tile común desde &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, el código debe preparar ese valor.&lt;br /&gt;
&lt;br /&gt;
Antes de añadir una pieza, se comprueba si puede verse en pantalla y si queda espacio de OAM. Tener una pose cargada no garantiza que puedan dibujarse todas sus piezas.&lt;br /&gt;
&lt;br /&gt;
=== Prioridad de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El sistema organiza las piezas según la prioridad de dibujo. En LoROM lleva su propio control de las entradas disponibles; en SA-1 utiliza la integración con MaxTile.&lt;br /&gt;
&lt;br /&gt;
Esta prioridad decide el orden entre piezas de sprites. No es lo mismo que la propiedad que determina si un tile queda delante o detrás de las capas del nivel.&lt;br /&gt;
&lt;br /&gt;
La organización de OAM ayuda a utilizar su espacio, pero no elimina el límite de sprites y tiles que SNES puede mostrar en una misma línea.&lt;br /&gt;
&lt;br /&gt;
== Jugador y Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
El jugador original tiene rutinas propias para elegir y cargar las piezas de sus poses. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; permite integrar ese trabajo con las cargas de Dynamic Xtreme y cambiar el origen de sus gráficos y paletas.&lt;br /&gt;
&lt;br /&gt;
Con el formato original, el juego sigue eligiendo las piezas de la pose. La rutina obtiene sus direcciones desde el origen configurado y compara esas direcciones con las anteriores para cargar las que hayan cambiado.&lt;br /&gt;
&lt;br /&gt;
Estas cargas utilizan transferencias forzadas y sus bytes también cuentan para las solicitudes normales posteriores. Así conservan su prioridad sin quedar fuera de la contabilidad del sistema.&lt;br /&gt;
&lt;br /&gt;
La paleta del jugador tiene un tratamiento especial: combina colores y selecciones del propio juego con el origen personalizado. No funciona simplemente como sustituir una paleta completa de un sprite cualquiera.&lt;br /&gt;
&lt;br /&gt;
El soporte para jugadores personalizados permite que otros sistemas administren de otra forma sus poses y dibujo. No convierte automáticamente cualquier spritesheet al formato del jugador original.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi también carga sus gráficos por piezas. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; permite cambiar su origen manteniendo la organización que esperan sus rutinas.&lt;br /&gt;
&lt;br /&gt;
El código calcula qué partes necesita y prepara sus cargas a los destinos correspondientes de VRAM. Como las del jugador, estas cargas tienen un tratamiento prioritario.&lt;br /&gt;
&lt;br /&gt;
Esta opción necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad. No permite evitar un conflicto del sistema del jugador habilitando únicamente las funciones de Yoshi.&lt;br /&gt;
&lt;br /&gt;
== Memoria y optimizaciones ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW mantiene en RAM gráficos originales del jugador, Yoshi y ciertas animaciones. En ROMs sin SA-1, esta opción adapta las cargas para leer esos datos desde ROM.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aprovecha la RAM recuperada para sus variables internas. No es un espacio que quede libre para que cualquier otro código escriba encima.&lt;br /&gt;
&lt;br /&gt;
SA-1 utiliza otras direcciones y desactiva esta opción. Los rangos están en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
Esta opción mueve el procesamiento del control desde NMI a la parte de game mode. El objetivo es dejar más tiempo para las actualizaciones de pantalla, no añadir un frame de retraso ni cambiar los botones que recibe el juego.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
El color fijo se utiliza en las mezclas de color de la consola. Para actualizarlo, el juego prepara sus componentes y los envía al registro correspondiente.&lt;br /&gt;
&lt;br /&gt;
La optimización reemplaza esa preparación por una secuencia más corta. El color sigue enviándose a la consola, pero necesita menos trabajo durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic utiliza listas llamadas stripe images para actualizar partes de los mapas de tiles. Esas listas incluyen tanto los datos como la información sobre sus destinos.&lt;br /&gt;
&lt;br /&gt;
La versión integrada de la optimización de Kevin prepara fuera de NMI parte del ajuste de esos destinos. Así deja menos trabajo de preparación para el momento de la transferencia.&lt;br /&gt;
&lt;br /&gt;
Esta opción sustituye el uso del parche original por separado. Además, no debe desinstalarse después de instalarla; hay que tenerlo en cuenta antes de activarla.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
La barra de estado original actualiza zonas concretas de VRAM. Esta opción prepara sus transferencias de forma más directa, reduciendo la configuración de DMA que necesita hacer durante NMI.&lt;br /&gt;
&lt;br /&gt;
No añade una barra nueva. Modifica la actualización de la original y, por eso, entra en conflicto con recursos que la reemplazan, modifican o eliminan.&lt;br /&gt;
&lt;br /&gt;
== Sprites dinámicos: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
El sistema utiliza el espacio disponible de VRAM como una caché de poses. Conserva las que ya cargó para reutilizarlas y busca cuáles puede reemplazar cuando hace falta espacio.&lt;br /&gt;
&lt;br /&gt;
En lugar de darle a cada sprite un espacio fijo para todos sus gráficos, permite que pida la pose que necesita en ese momento.&lt;br /&gt;
&lt;br /&gt;
=== Una pose para varias entidades ===&lt;br /&gt;
&lt;br /&gt;
Si cinco sprites piden la misma pose, no hacen falta cinco copias de sus gráficos. La primera solicitud puede cargarla y las siguientes encuentran esa misma pose registrada. Después cada sprite la dibuja en su propia posición.&lt;br /&gt;
&lt;br /&gt;
La búsqueda utiliza el ID de la pose. Dos recursos con gráficos visualmente iguales no se consideran necesariamente la misma pose si tienen IDs distintos.&lt;br /&gt;
&lt;br /&gt;
=== Encontrar una pose que ya está cargada ===&lt;br /&gt;
&lt;br /&gt;
El sistema guarda el ID de cada pose registrada, su lugar en VRAM y el momento en que se utilizó por última vez.&lt;br /&gt;
&lt;br /&gt;
Para encontrarla utiliza una tabla hash de 128 entradas. Esto significa que el ID permite calcular dónde comenzar la búsqueda, en lugar de recorrer siempre todas las poses. Después se compara el ID completo para confirmar que es la correcta.&lt;br /&gt;
&lt;br /&gt;
Si la encuentra, guarda el valor actual de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; en su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt;. Así queda marcada como utilizada en este frame y no puede ser reemplazada hasta cumplir el tiempo mínimo de protección. No se programa otra transferencia de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
=== Cuando la pose todavía no está ===&lt;br /&gt;
&lt;br /&gt;
Para una pose nueva, el sistema consulta las tablas generadas desde el DynamicInfo:&lt;br /&gt;
&lt;br /&gt;
# Obtiene el tamaño de sus gráficos y comprueba el presupuesto del frame.&lt;br /&gt;
# Busca espacio para los bloques de VRAM que necesita.&lt;br /&gt;
# Retira las referencias de las poses que tenga que reemplazar.&lt;br /&gt;
# Registra la nueva pose y el lugar elegido.&lt;br /&gt;
# Prepara las transferencias de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
Si no hay presupuesto o no encuentra espacio adecuado, la solicitud falla. El código que pidió la pose puede intentarlo después.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se reparte VRAM ===&lt;br /&gt;
&lt;br /&gt;
El mapa de espacio distingue zonas reservadas, regiones libres y regiones ocupadas por poses. La reserva se mide en bloques de gráficos de 16×16.&lt;br /&gt;
&lt;br /&gt;
Las configuraciones de espacio deciden qué partes de SP1-SP4 pueden utilizarse. Una región reservada para el jugador, gráficos fijos u otro sistema no puede elegirse para una pose nueva.&lt;br /&gt;
&lt;br /&gt;
El mapa guarda dónde comienza cada región y cuánto ocupa. Puede dividir un espacio libre grande para colocar una pose y dejar el resto disponible. También puede considerar regiones contiguas para reunir el espacio necesario.&lt;br /&gt;
&lt;br /&gt;
=== Qué poses se pueden reemplazar ===&lt;br /&gt;
&lt;br /&gt;
Que una pose no se solicite en un frame no significa que deba sobrescribirse inmediatamente. El sistema protege las utilizadas recientemente y exige al menos dos frames de antigüedad para considerar su espacio.&lt;br /&gt;
&lt;br /&gt;
Entre los espacios que puede utilizar, favorece los que llevan más tiempo sin uso. Si la antigüedad es equivalente, prefiere el espacio suficiente más pequeño, dejando las regiones mayores para otras poses.&lt;br /&gt;
&lt;br /&gt;
Cuando una región reúne varias poses, la protección de todas ellas cuenta. No se puede reemplazar una parte que todavía esté protegida solo porque la pose de al lado sea antigua.&lt;br /&gt;
&lt;br /&gt;
Una pose que dejó de utilizarse puede quedarse en VRAM y continuar registrada. Si vuelve a solicitarse antes de ser reemplazada, se reutiliza sin otra carga.&lt;br /&gt;
&lt;br /&gt;
=== Conservar la pose anterior ===&lt;br /&gt;
&lt;br /&gt;
Si no se puede cargar una pose nueva, las rutinas de sprites pueden seguir utilizando una pose anterior válida. También mantienen su protección para que no se sobrescriba mientras se sigue dibujando.&lt;br /&gt;
&lt;br /&gt;
Esto explica una diferencia importante: una llamada puede devolver una pose utilizable sin haber conseguido todavía la pose nueva.&lt;br /&gt;
&lt;br /&gt;
Si el sprite nunca tuvo una pose válida, no hay una anterior que mostrar. Su código debe comprobar el resultado antes de dibujar.&lt;br /&gt;
&lt;br /&gt;
=== La lógica sigue siendo del sprite ===&lt;br /&gt;
&lt;br /&gt;
La caché no decide cuándo camina, salta o cambia de animación un personaje. El sprite elige la pose, solicita sus gráficos y dibuja con el resultado disponible.&lt;br /&gt;
&lt;br /&gt;
La separación entre short routine y long routine permite evitar parte del trabajo gráfico cuando el sprite no necesita dibujarse. La short routine conserva la lógica correspondiente; la long routine incluye el manejo de paleta, pose y dibujo.&lt;br /&gt;
&lt;br /&gt;
== Efectos de paleta: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
Para cambiar un efecto sin estropear los colores, el sistema tiene que conservar una base. Si cada cambio se aplicara sobre el resultado ya afectado del frame anterior, el color podría ir acumulando modificaciones que no se buscaban.&lt;br /&gt;
&lt;br /&gt;
Por eso se distinguen los colores originales, las versiones preparadas para el cálculo y el resultado que se va a mostrar.&lt;br /&gt;
&lt;br /&gt;
=== Conservar los colores originales ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; guarda la base en formato de SNES. A partir de ella se preparan las representaciones RGB o HSL cuando hacen falta.&lt;br /&gt;
&lt;br /&gt;
RGB separa rojo, verde y azul. HSL separa tono, saturación y luminosidad. Ambas utilizan tres bytes por color; los colores de SNES utilizan dos.&lt;br /&gt;
&lt;br /&gt;
El resultado convertido de nuevo al formato de SNES se guarda en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;, que corresponde al buffer de paletas del juego.&lt;br /&gt;
&lt;br /&gt;
El sistema lleva indicadores para saber qué bases ya tiene preparadas. Si se pasa de un efecto RGB a uno HSL, no debe tomar los colores afectados como si fueran los originales.&lt;br /&gt;
&lt;br /&gt;
=== Preparar la base cuando hace falta ===&lt;br /&gt;
&lt;br /&gt;
Una paleta sin base registrada puede obtener sus colores del buffer del juego. Una carga explícita, como &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, proporciona los colores que deben utilizarse como base.&lt;br /&gt;
&lt;br /&gt;
La conversión a RGB o HSL se hace cuando se necesita. Después puede reutilizarse mientras no cambien los colores de origen.&lt;br /&gt;
&lt;br /&gt;
Cuando llegan colores nuevos, las conversiones y efectos anteriores dejan de servir. Las llamadas correspondientes de carga actualizan la base y borran los indicadores que deben volver a calcularse.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto ===&lt;br /&gt;
&lt;br /&gt;
El ID del efecto permite leer su tipo, valores y ratios en las tablas preparadas al instalar.&lt;br /&gt;
&lt;br /&gt;
Los canales utilizan valores de 0 a 31. Los ratios van de 0 a 127: 0 conserva el origen y 127 aplica por completo el cambio elegido.&lt;br /&gt;
&lt;br /&gt;
Un efecto puede modificar un canal, varios canales o mezclar los colores con los de otra paleta. Las transiciones utilizan los destinos RGB o HSL que ya se prepararon durante la instalación.&lt;br /&gt;
&lt;br /&gt;
Los cálculos se hacen fuera de NMI. La parte de NMI se encarga de copiar los colores resultantes, no de calcular cada efecto durante la transferencia.&lt;br /&gt;
&lt;br /&gt;
=== El efecto global ===&lt;br /&gt;
&lt;br /&gt;
El juego selecciona un ID global y elige mediante máscaras qué paletas deben recibirlo. El color fijo y el color 0,0 tienen sus propios indicadores.&lt;br /&gt;
&lt;br /&gt;
El administrador comprueba si cada paleta necesita una actualización. Si la base no cambió y sigue siendo válido el resultado del mismo efecto, puede reutilizarlo.&lt;br /&gt;
&lt;br /&gt;
Al cambiar el ID global, los resultados del efecto anterior dejan de servir, pero las bases RGB y HSL pueden seguir siendo válidas si sus colores de origen no cambiaron.&lt;br /&gt;
&lt;br /&gt;
Poner el ID global en 0 permite volver a los colores de base. Para restaurarlos, el sistema todavía tiene que procesar las paletas afectadas; no basta con dejar de trabajar sobre ellas.&lt;br /&gt;
&lt;br /&gt;
=== Combinar un efecto local con el global ===&lt;br /&gt;
&lt;br /&gt;
Un sprite puede necesitar un cambio de color propio y, además, recibir el efecto general del nivel. Por ejemplo, puede cambiar de tono y después oscurecerse junto con el resto de la pantalla.&lt;br /&gt;
&lt;br /&gt;
Las llamadas de concatenación permiten preparar el resultado local como base del efecto global. La variante RGB se utiliza con efectos RGB; la HSL, con efectos HSL.&lt;br /&gt;
&lt;br /&gt;
No hay que mostrar primero el resultado local sin el efecto global. Se prepara la base para que la carga final ya contenga la combinación correspondiente.&lt;br /&gt;
&lt;br /&gt;
Los recursos que comparten una paleta de CGRAM también comparten sus colores. Dos sprites que necesiten efectos locales diferentes deben disponer de destinos adecuados para mostrar ambos resultados.&lt;br /&gt;
&lt;br /&gt;
=== Cargar el resultado ===&lt;br /&gt;
&lt;br /&gt;
Cuando los colores están preparados, se solicita su transferencia a CGRAM. Esa carga también puede quedar pendiente si no se acepta por el presupuesto.&lt;br /&gt;
&lt;br /&gt;
Preparar una base o calcular un efecto no significa que ya esté en pantalla. El administrador confirma sus cambios de estado según el resultado de la carga y puede volver a intentar una actualización pendiente.&lt;br /&gt;
&lt;br /&gt;
Cuando corresponde, se mantiene un resultado anterior utilizable hasta poder sustituirlo. Esto permite distinguir una paleta que todavía está cambiando de una que nunca tuvo colores disponibles para mostrarse.&lt;br /&gt;
&lt;br /&gt;
Cargar directamente los colores originales antes del efecto podría hacer que se vieran un frame sin él. Por eso las cargas destinadas al efecto global preparan la base y dejan que se muestre el resultado ya procesado.&lt;br /&gt;
&lt;br /&gt;
== Cómo trabajan juntos ==&lt;br /&gt;
&lt;br /&gt;
Un sprite dinámico utiliza varias de estas partes durante el mismo frame. Su lógica elige una pose y una paleta; la asignación encuentra colores utilizables; la caché encuentra o prepara los gráficos; y el dibujo coloca sus piezas.&lt;br /&gt;
&lt;br /&gt;
Después, el administrador de efectos prepara los cambios globales que hagan falta y NMI realiza las transferencias solicitadas.&lt;br /&gt;
&lt;br /&gt;
Compartir gráficos, compartir una paleta y compartir una rutina de dibujo son tres cosas distintas. Dynamic Xtreme puede aprovechar cada una sin obligar a que los recursos compartan también las demás.&lt;br /&gt;
&lt;br /&gt;
== Lecturas relacionadas ==&lt;br /&gt;
&lt;br /&gt;
* [[es/Dynamic_Xtreme|Artículo principal]]: funcionalidades y compatibilidad.&lt;br /&gt;
* [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_sprite_creation_guide|Creación de sprites dinámicos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_UberASM_guide|Dynamic Xtreme con UberASM]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_ASM_API|API ASM]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21369</id>
		<title>es/Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21369"/>
		<updated>2026-10-25T01:31:05Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo funciona Dynamic Xtreme, desde la preparación de los recursos al instalarlo hasta la carga y el dibujo de una pose durante el juego.&lt;br /&gt;
&lt;br /&gt;
== Qué prepara la instalación ==&lt;br /&gt;
&lt;br /&gt;
Antes de que un sprite pueda usar sus gráficos o una paleta, Dynamic Xtreme tiene que guardarlos en la ROM y preparar la información para encontrarlos. Lo mismo ocurre con cualquier otro recurso dinámico que hayas añadido.&lt;br /&gt;
&lt;br /&gt;
Para hacerlo, la herramienta lee los DynamicInfo, DrawInfo y PaletteEffect. Cada archivo aporta una parte distinta: qué recursos se van a cargar, cómo se dibujan las poses y qué cambios de color se pueden aplicar.&lt;br /&gt;
&lt;br /&gt;
Gracias a esta preparación se generan defines en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permiten utilizar los recursos y ejecutar fácilmente las rutinas necesarias.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: recursos y datos de carga ===&lt;br /&gt;
&lt;br /&gt;
Un DynamicInfo reúne los gráficos de poses, las paletas y los recursos generales que necesita un sprite u otro código. Si incluye gráficos de poses dinámicas, la herramienta los organiza para que puedan cargarse con la distribución de tiles que espera el sistema.&lt;br /&gt;
&lt;br /&gt;
Por cada pose guarda varios datos en tablas separadas. Todas mantienen el mismo orden: la entrada de una pose en una tabla corresponde a esa misma pose en las demás.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || La cantidad de datos que utiliza cada pose, en bytes. Se utiliza para comprobar si su carga cabe en el presupuesto del frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || Cuántos bloques de 16×16 hay que reservar en VRAM para la pose. No siempre coincide exactamente con los bytes que se copian, porque una pieza incompleta también puede necesitar un bloque de espacio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || La dirección de los gráficos de cada pose en ROM. Incluye el banco, de modo que el código de carga pueda encontrar su origen completo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || Dos tamaños por pose, correspondientes a los dos tramos en que pueden dividirse sus gráficos. La rutina de carga utiliza esos tamaños para repartirlos correctamente en VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || El desplazamiento en VRAM desde el comienzo del primer tramo hasta el comienzo del segundo. Permite colocar el segundo tramo donde corresponde, aunque el primero termine con una fila incompleta.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas describen todas las poses instaladas, no solo las que están en pantalla. Más adelante, la caché guarda por separado cuáles están cargadas y dónde quedaron.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si se solicita una pose que todavía no está en VRAM, el sistema consulta cuántos bytes necesita cargar, busca espacio para sus bloques y utiliza la dirección y los datos de sus tramos para preparar la carga.&lt;br /&gt;
&lt;br /&gt;
==== Tablas de paletas ====&lt;br /&gt;
&lt;br /&gt;
Las paletas declaradas en los DynamicInfo se reúnen en &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. Esta tiene dos partes:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; guarda el ID de cada paleta.&lt;br /&gt;
* &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; guarda dónde están sus colores en ROM.&lt;br /&gt;
&lt;br /&gt;
Las dos listas siguen el orden de las paletas de los DynamicInfo. El define de offset de cada DynamicInfo indica dónde comienza su lista dentro de ellas. Al elegir una versión, el sistema suma ese índice al offset y obtiene tanto el ID como la dirección de los colores elegidos.&lt;br /&gt;
&lt;br /&gt;
El ID permite reconocer y compartir una paleta; la dirección permite cargarla. No son el número de paleta de pantalla: una misma paleta instalada puede terminar, por ejemplo, en la paleta 9 o en la C según la asignación.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y defines ====&lt;br /&gt;
&lt;br /&gt;
Los archivos declarados en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; se guardan en ROM. Su dirección y la cantidad de bytes que ocupan pueden consultarse mediante los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Por ejemplo, para &amp;lt;code&amp;gt;my_resource.bin&amp;lt;/code&amp;gt; se generan:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt;: dirección del recurso en ROM.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt;: cantidad de bytes que ocupa.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt;: ID del recurso.&lt;br /&gt;
&lt;br /&gt;
El nombre se normaliza en PascalCase: se eliminan espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: datos y rutinas de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El DrawInfo describe cómo está formada una pose: qué tiles tiene, dónde se coloca cada uno, qué tamaño utiliza y cómo cambia al voltearse.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, Dynamic Xtreme genera rutinas de dibujo optimizadas según los parámetros que utilizan los tiles. Tiene en cuenta, por ejemplo, si necesitan desplazamientos X e Y, si comparten el mismo tamaño, si utilizan propiedades comunes y si requieren volteos.&lt;br /&gt;
&lt;br /&gt;
De esta forma, la rutina realiza el trabajo que necesita ese dibujo sin añadir el manejo de opciones que no utiliza. Varias poses pueden compartirla si necesitan el mismo tratamiento; eso no significa que compartan también sus gráficos o su ID.&lt;br /&gt;
&lt;br /&gt;
La relación entre una pose y su dibujo se guarda en estas tablas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || Dónde comienzan los datos de la pose dentro de las tablas de su rutina de dibujo. Así se localizan sus tiles y desplazamientos sin recorrer las poses anteriores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || La cantidad de tiles de la pose menos uno. Una pose de cuatro tiles guarda 3; la rutina utiliza ese valor para recorrer sus piezas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || Qué rutina de dibujo utiliza cada pose. Las poses con características compatibles pueden apuntar al mismo ID de rutina.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || Las direcciones de las rutinas de dibujo. El ID de rutina permite encontrar aquí el código que debe ejecutarse.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada rutina tiene, además, las tablas que necesitan sus poses:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos !! Qué describen&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || Los números de tile que forman la pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || Las propiedades de cada pieza, como los volteos y su prioridad respecto a las capas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || La posición de cada tile respecto al punto de origen de la pose.&lt;br /&gt;
|-&lt;br /&gt;
| Tablas de desplazamientos para los volteos || Las posiciones que deben utilizarse al voltear la pose cuando necesita una distribución distinta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || El tamaño de cada tile: 8×8 o 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
No todas estas tablas tienen que aparecer en todas las rutinas. Si un dato es igual para todas las piezas o puede obtenerse de un valor común, la herramienta puede generar una rutina que lo utilice directamente.&lt;br /&gt;
&lt;br /&gt;
La optimización se hace durante la instalación. Si todos los tiles tienen el mismo tamaño, por ejemplo, la rutina puede utilizar ese valor común sin leer un tamaño distinto para cada pieza.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: datos de los efectos ===&lt;br /&gt;
&lt;br /&gt;
Un archivo PaletteEffect contiene una lista de cambios de color. La instalación les asigna IDs y guarda sus datos en &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Como en las tablas de poses, los datos de cada efecto mantienen la misma posición en las distintas listas. Los IDs de efectos comienzan en 1; el ID 0 se utiliza para indicar que no hay efecto global.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parte de la tabla !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || La cantidad de efectos instalados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || El tipo de cada efecto, por ejemplo &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Indica qué cálculo debe realizarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || Los valores de los canales que utiliza el efecto. En una transición, estos tres bytes guardan la dirección de la paleta de destino, no valores de canales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || Cuánto se aplica el cambio en cada componente. Van de 0 a 127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Si el efecto es una transición hacia otra paleta, la herramienta también prepara esa paleta. Convierte sus colores al formato RGB o HSL que necesita la transición y los guarda en ROM. Durante el juego se puede utilizar ese destino sin tener que convertirlo de nuevo en cada llamada.&lt;br /&gt;
&lt;br /&gt;
Estas paletas de transición son distintas de las paletas normales que se cargan a CGRAM: contienen tres componentes por color y se utilizan para calcular el efecto.&lt;br /&gt;
&lt;br /&gt;
=== Cómo encuentra el código los recursos instalados ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; publica los IDs, direcciones, tamaños y offsets que necesitan los recursos. Por ejemplo, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifica una pose y &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifica el primer efecto de un archivo.&lt;br /&gt;
&lt;br /&gt;
Los nombres se normalizan en PascalCase: se eliminan separadores como espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra. &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, por ejemplo, pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También se genera &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, que guarda las direcciones de los bloques donde se insertaron los recursos. La herramienta utiliza esa información para localizar los datos de una instalación anterior al reinstalar.&lt;br /&gt;
&lt;br /&gt;
Una reinstalación puede cambiar IDs y direcciones. Por eso hay que volver a insertar los sprites, bloques y códigos UberASM que utilizan los defines generados.&lt;br /&gt;
&lt;br /&gt;
== El trabajo de cada frame ==&lt;br /&gt;
&lt;br /&gt;
En la lógica principal se ejecutan el jugador, los sprites y los demás códigos del modo de juego. Los que utilizan Dynamic Xtreme solicitan las poses y paletas que necesitan, preparan los efectos locales y llaman a las rutinas de dibujo. Las cargas que se aceptan quedan anotadas para transferir sus datos durante NMI.&lt;br /&gt;
&lt;br /&gt;
Al terminar esa lógica, el código de game mode de Dynamic Xtreme realiza las tareas que correspondan a las opciones habilitadas: prepara las actualizaciones de VRAM de la optimización de Kevin, mantiene el estado de las paletas y calcula los efectos globales pendientes.&lt;br /&gt;
&lt;br /&gt;
Después, durante NMI, se ejecutan las transferencias preparadas: los gráficos se copian a VRAM y los colores a CGRAM. También se reinicia el contador de datos y se actualizan los relojes del sistema para el siguiente ciclo de trabajo.&lt;br /&gt;
&lt;br /&gt;
El orden que seguiremos para explicarlo es, por tanto, &#039;&#039;&#039;lógica principal → tareas al terminar el game mode → transferencias durante NMI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Lógica principal ===&lt;br /&gt;
&lt;br /&gt;
Cada recurso decide qué necesita. Un sprite puede cambiar de pose, una animación puede pedir nuevos gráficos y un código UberASM puede cargar una paleta o seleccionar un efecto.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme atiende esas solicitudes utilizando sus distintos sistemas. Por ejemplo, si una pose ya está cargada, devuelve su ubicación sin copiar otra vez los gráficos. Si necesita cargarla, comprueba el presupuesto y el espacio disponible antes de preparar la transferencia.&lt;br /&gt;
&lt;br /&gt;
El dibujo también se prepara en esta parte: las rutinas escriben en los buffers OAM la posición, los tiles y las propiedades de las piezas que se mostrarán.&lt;br /&gt;
&lt;br /&gt;
Una solicitud puede rechazarse, por ejemplo si no queda presupuesto para sus datos. El recurso que la pidió debe comprobar el resultado y decidir si conserva lo anterior o vuelve a intentarlo después. Una carga rechazada no queda guardada automáticamente para otro frame.&lt;br /&gt;
&lt;br /&gt;
=== Tareas de game mode ===&lt;br /&gt;
&lt;br /&gt;
SMW separa estados como la carga del nivel, el juego dentro del nivel y las transiciones mediante game modes. El número del modo actual está en &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;DXGameMode&amp;lt;/code&amp;gt; rodea la ejecución del modo actual con el trabajo de Dynamic Xtreme. Antes de llamar a la lógica del modo, procesa el control si está habilitada su optimización y comprueba si el sistema debe estar activo en esa pantalla.&lt;br /&gt;
&lt;br /&gt;
Si el modo no está permitido, reinicializa listas, contadores y el estado de sus sistemas. Este reinicio puede repetirse mientras el juego permanezca allí; no depende únicamente de detectar que cambió el número de modo.&lt;br /&gt;
&lt;br /&gt;
Cuando termina la lógica del modo, continúa con estas tareas, según las funciones instaladas:&lt;br /&gt;
&lt;br /&gt;
# La optimización de VRAM de Kevin prepara los destinos de las actualizaciones de Lunar Magic.&lt;br /&gt;
# El sistema de paletas limpia sus marcas de actualización y reduce los temporizadores de protección, cuando corresponde.&lt;br /&gt;
# El sistema de efectos revisa las paletas habilitadas, calcula los resultados que hagan falta y prepara sus cargas.&lt;br /&gt;
&lt;br /&gt;
Los efectos globales se procesan después de los cambios que hayan preparado los sprites y otros códigos. Así pueden trabajar sobre las nuevas bases de color antes de enviar el resultado a pantalla.&lt;br /&gt;
&lt;br /&gt;
El mantenimiento de paletas comprueba además el modo de juego y la pausa antes de continuar. Algunas llamadas de sprites tienen sus propias comprobaciones de modo, más restrictivas que las generales.&lt;br /&gt;
&lt;br /&gt;
=== Transferencias durante NMI ===&lt;br /&gt;
&lt;br /&gt;
NMI es una interrupción que SNES puede generar al comenzar VBlank, después de dibujar la parte visible de la pantalla. El juego aprovecha ese intervalo para actualizar gráficos, colores y otros datos de video.&lt;br /&gt;
&lt;br /&gt;
En los modos permitidos, la rutina de Dynamic Xtreme reinicia &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; y actualiza sus relojes. Después ejecuta las transferencias de gráficos pendientes y luego las de paletas. Si corresponde, también actualiza el color 0,0 preparado por el sistema de efectos.&lt;br /&gt;
&lt;br /&gt;
Las copias utilizan DMA, el mecanismo de la consola para transferir los datos. Los cálculos de poses y efectos ya se hicieron antes; durante esta parte se utilizan los orígenes, destinos y cantidades que quedaron preparados.&lt;br /&gt;
&lt;br /&gt;
El tiempo de VBlank es limitado y también lo utilizan las tareas normales de pantalla de SMW. Por eso es importante controlar cuántos datos se solicitan y evitar trabajo innecesario dentro de NMI.&lt;br /&gt;
&lt;br /&gt;
==== Las listas de transferencias ====&lt;br /&gt;
&lt;br /&gt;
Cada transferencia guarda el origen de los datos, su banco, la cantidad de bytes y el destino en VRAM o CGRAM.&lt;br /&gt;
&lt;br /&gt;
Al realizar las copias, NMI recorre las listas desde la última entrada hacia la primera y después las vacía. Esto no borra los gráficos o colores cargados: permanecen en su destino hasta que otro código los cambie.&lt;br /&gt;
&lt;br /&gt;
La lista de VRAM utiliza 0 cuando no tiene entradas. La de CGRAM utiliza &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, porque guarda el índice de la última entrada en lugar de guardar directamente su cantidad.&lt;br /&gt;
&lt;br /&gt;
Si dos códigos escriben sobre el mismo destino, deben coordinar sus cargas. El orden de las solicitudes no debe utilizarse como sustituto de decidir qué recurso puede ocupar cada espacio.&lt;br /&gt;
&lt;br /&gt;
Cuando el origen está en RAM, los datos deben conservarse hasta que se ejecute la transferencia. Cambiarlos antes puede hacer que se copie algo distinto de lo solicitado.&lt;br /&gt;
&lt;br /&gt;
==== Presupuesto de datos ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; suma los bytes comprometidos por las cargas del sistema. Las solicitudes normales lo comparan con &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; antes de aceptarse.&lt;br /&gt;
&lt;br /&gt;
El límite predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Controla la cantidad de datos solicitados, pero no representa una medida exacta del tiempo que tardará cualquier combinación de transferencias.&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; omiten esa comprobación y también suman sus bytes al contador. Permiten dar prioridad a ciertas cargas; no aumentan el tiempo disponible de la consola.&lt;br /&gt;
&lt;br /&gt;
==== Los dos relojes ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza cada vez que se ejecuta la rutina correspondiente de Dynamic Xtreme en un modo permitido. Sigue contando durante la pausa y permite saber cuánto lleva una pose sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; se detiene durante la pausa y cuando se congela la acción. Puede utilizarse para animaciones que deban detenerse junto con el juego.&lt;br /&gt;
&lt;br /&gt;
== Carga de gráficos: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; permite programar cargas de gráficos a VRAM. Lo utilizan las animaciones de tiles, las poses dinámicas y las rutinas de gráficos del jugador y Yoshi.&lt;br /&gt;
&lt;br /&gt;
La idea básica es sencilla: el código indica qué datos quiere copiar y dónde quiere ponerlos. Si la solicitud se acepta, se añade a la lista y sus bytes cuentan para el presupuesto del frame.&lt;br /&gt;
&lt;br /&gt;
Esta parte no elige la siguiente imagen de una animación ni reparte por sí sola el espacio entre sprites. Esas decisiones las toma el código que solicita la carga o el administrador de poses dinámicas.&lt;br /&gt;
&lt;br /&gt;
=== Animaciones en un destino fijo ===&lt;br /&gt;
&lt;br /&gt;
Una animación puede cambiar los gráficos de unos tiles sin cambiar sus números. Para ello copia cada imagen al mismo lugar de VRAM.&lt;br /&gt;
&lt;br /&gt;
El código de animación elige la imagen y pide su carga. Si no se acepta, puede mantener la imagen anterior y esperar al siguiente intento.&lt;br /&gt;
&lt;br /&gt;
Así la animación tiene en cuenta las demás cargas del frame en lugar de copiar sus gráficos sin importar cuánto trabajo se había pedido.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se colocan los gráficos de una pose ===&lt;br /&gt;
&lt;br /&gt;
Los gráficos de una pose pueden necesitar varias transferencias para quedar en las filas de tiles correctas. No siempre se pueden copiar como un bloque seguido a partir de una única dirección de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; utiliza los tamaños y desplazamientos preparados al instalar. Recibe el lugar elegido para la pose, calcula los destinos y añade las transferencias necesarias.&lt;br /&gt;
&lt;br /&gt;
Encontrar ese lugar y decidir si puede utilizarse es el trabajo de la caché, que se explica más adelante. La rutina de carga se ocupa de colocar los gráficos en él.&lt;br /&gt;
&lt;br /&gt;
== Carga y asignación de paletas: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
Una paleta instalada es un conjunto de colores guardados en ROM. Una paleta de pantalla es el lugar de CGRAM donde se colocan esos colores para dibujar.&lt;br /&gt;
&lt;br /&gt;
Un sprite puede pedir su paleta azul sin exigir que siempre ocupe la paleta 9. La asignación automática puede encontrarle un destino entre las paletas de sprites que tenga permitidas.&lt;br /&gt;
&lt;br /&gt;
=== Cargar colores ===&lt;br /&gt;
&lt;br /&gt;
La copia a CGRAM se prepara de forma parecida a una carga de gráficos: necesita un origen, un primer color de destino y una cantidad de bytes. Cada color de SNES ocupa dos bytes.&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; también actualizan las copias de colores del juego. Esto es importante porque SMW puede volver a utilizarlas, por ejemplo durante la animación de victoria del goal. Cambiar solo CGRAM dejaría esas copias con los colores anteriores.&lt;br /&gt;
&lt;br /&gt;
Cuando la paleta debe recibir un efecto global, se guardan primero sus colores originales. El sistema calcula el efecto sobre ellos y carga el resultado, sin mostrar antes una versión sin efecto.&lt;br /&gt;
&lt;br /&gt;
=== Encontrar una paleta disponible ===&lt;br /&gt;
&lt;br /&gt;
Para asignar un destino, el sistema busca primero una paleta con el mismo ID y una condición de efecto compatible. Si ya existe, puede compartirla en lugar de cargar otra copia.&lt;br /&gt;
&lt;br /&gt;
Si no la encuentra, busca una entrada libre. Si tampoco hay una libre, puede reemplazar una que haya dejado de estar protegida.&lt;br /&gt;
&lt;br /&gt;
Cada entrada guarda qué ID utiliza y un temporizador de protección. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; significa que está libre; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; significa que está reservada y que la asignación automática no debe ocuparla.&lt;br /&gt;
&lt;br /&gt;
Mientras un recurso utiliza su paleta, mantiene ese temporizador en 2. Así otro recurso no la reemplaza entre un frame y el siguiente.&lt;br /&gt;
&lt;br /&gt;
Cuando el temporizador llega a cero, los colores no desaparecen. Si alguien vuelve a pedir la misma paleta antes de que se reemplace, todavía puede aprovechar esa asignación.&lt;br /&gt;
&lt;br /&gt;
=== Asignación manual y versión ===&lt;br /&gt;
&lt;br /&gt;
En modo manual, el código elige el destino. Puede cargar allí sus colores o utilizar los que ya estaban preparados en el nivel. Si dos recursos eligen ese destino con colores distintos, tendrán que coordinarse para no sobrescribirse.&lt;br /&gt;
&lt;br /&gt;
En las rutinas de sprites, la versión elige una entrada de la lista de paletas del DynamicInfo. La última versión procesada permite saber si esa selección cambió.&lt;br /&gt;
&lt;br /&gt;
Mantener una paleta en uso no implica volver a cargarla cada frame. Si sigue siendo válida, lo que se mantiene es su protección.&lt;br /&gt;
&lt;br /&gt;
== Dibujo de poses: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
Tener los gráficos en VRAM no hace que un sprite aparezca por sí solo. También hay que indicar qué tiles lo forman, dónde van y con qué propiedades se muestran.&lt;br /&gt;
&lt;br /&gt;
Ese es el trabajo del dibujo. El sistema toma la pose del DrawInfo y prepara sus piezas en OAM, la memoria que utiliza la consola para colocar los sprites en pantalla.&lt;br /&gt;
&lt;br /&gt;
=== De los datos a las piezas visibles ===&lt;br /&gt;
&lt;br /&gt;
La rutina suma a la posición del sprite los desplazamientos de cada tile. También aplica los volteos y combina la paleta y las demás propiedades necesarias.&lt;br /&gt;
&lt;br /&gt;
En una pose dinámica, ajusta los tiles al lugar donde quedaron cargados sus gráficos. En una pose estática, utiliza sus posiciones fijas. Si el dibujo toma un tile común desde &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, el código debe preparar ese valor.&lt;br /&gt;
&lt;br /&gt;
Antes de añadir una pieza, se comprueba si puede verse en pantalla y si queda espacio de OAM. Tener una pose cargada no garantiza que puedan dibujarse todas sus piezas.&lt;br /&gt;
&lt;br /&gt;
=== Prioridad de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El sistema organiza las piezas según la prioridad de dibujo. En LoROM lleva su propio control de las entradas disponibles; en SA-1 utiliza la integración con MaxTile.&lt;br /&gt;
&lt;br /&gt;
Esta prioridad decide el orden entre piezas de sprites. No es lo mismo que la propiedad que determina si un tile queda delante o detrás de las capas del nivel.&lt;br /&gt;
&lt;br /&gt;
La organización de OAM ayuda a utilizar su espacio, pero no elimina el límite de sprites y tiles que SNES puede mostrar en una misma línea.&lt;br /&gt;
&lt;br /&gt;
== Jugador y Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
El jugador original tiene rutinas propias para elegir y cargar las piezas de sus poses. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; permite integrar ese trabajo con las cargas de Dynamic Xtreme y cambiar el origen de sus gráficos y paletas.&lt;br /&gt;
&lt;br /&gt;
Con el formato original, el juego sigue eligiendo las piezas de la pose. La rutina obtiene sus direcciones desde el origen configurado y compara esas direcciones con las anteriores para cargar las que hayan cambiado.&lt;br /&gt;
&lt;br /&gt;
Estas cargas utilizan transferencias forzadas y sus bytes también cuentan para las solicitudes normales posteriores. Así conservan su prioridad sin quedar fuera de la contabilidad del sistema.&lt;br /&gt;
&lt;br /&gt;
La paleta del jugador tiene un tratamiento especial: combina colores y selecciones del propio juego con el origen personalizado. No funciona simplemente como sustituir una paleta completa de un sprite cualquiera.&lt;br /&gt;
&lt;br /&gt;
El soporte para jugadores personalizados permite que otros sistemas administren de otra forma sus poses y dibujo. No convierte automáticamente cualquier spritesheet al formato del jugador original.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi también carga sus gráficos por piezas. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; permite cambiar su origen manteniendo la organización que esperan sus rutinas.&lt;br /&gt;
&lt;br /&gt;
El código calcula qué partes necesita y prepara sus cargas a los destinos correspondientes de VRAM. Como las del jugador, estas cargas tienen un tratamiento prioritario.&lt;br /&gt;
&lt;br /&gt;
Esta opción necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad. No permite evitar un conflicto del sistema del jugador habilitando únicamente las funciones de Yoshi.&lt;br /&gt;
&lt;br /&gt;
== Memoria y optimizaciones ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW mantiene en RAM gráficos originales del jugador, Yoshi y ciertas animaciones. En ROMs sin SA-1, esta opción adapta las cargas para leer esos datos desde ROM.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aprovecha la RAM recuperada para sus variables internas. No es un espacio que quede libre para que cualquier otro código escriba encima.&lt;br /&gt;
&lt;br /&gt;
SA-1 utiliza otras direcciones y desactiva esta opción. Los rangos están en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
Esta opción mueve el procesamiento del control desde NMI a la parte de game mode. El objetivo es dejar más tiempo para las actualizaciones de pantalla, no añadir un frame de retraso ni cambiar los botones que recibe el juego.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
El color fijo se utiliza en las mezclas de color de la consola. Para actualizarlo, el juego prepara sus componentes y los envía al registro correspondiente.&lt;br /&gt;
&lt;br /&gt;
La optimización reemplaza esa preparación por una secuencia más corta. El color sigue enviándose a la consola, pero necesita menos trabajo durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic utiliza listas llamadas stripe images para actualizar partes de los mapas de tiles. Esas listas incluyen tanto los datos como la información sobre sus destinos.&lt;br /&gt;
&lt;br /&gt;
La versión integrada de la optimización de Kevin prepara fuera de NMI parte del ajuste de esos destinos. Así deja menos trabajo de preparación para el momento de la transferencia.&lt;br /&gt;
&lt;br /&gt;
Esta opción sustituye el uso del parche original por separado. Además, no debe desinstalarse después de instalarla; hay que tenerlo en cuenta antes de activarla.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
La barra de estado original actualiza zonas concretas de VRAM. Esta opción prepara sus transferencias de forma más directa, reduciendo la configuración de DMA que necesita hacer durante NMI.&lt;br /&gt;
&lt;br /&gt;
No añade una barra nueva. Modifica la actualización de la original y, por eso, entra en conflicto con recursos que la reemplazan, modifican o eliminan.&lt;br /&gt;
&lt;br /&gt;
== Sprites dinámicos: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
El sistema utiliza el espacio disponible de VRAM como una caché de poses. Conserva las que ya cargó para reutilizarlas y busca cuáles puede reemplazar cuando hace falta espacio.&lt;br /&gt;
&lt;br /&gt;
En lugar de darle a cada sprite un espacio fijo para todos sus gráficos, permite que pida la pose que necesita en ese momento.&lt;br /&gt;
&lt;br /&gt;
=== Una pose para varias entidades ===&lt;br /&gt;
&lt;br /&gt;
Si cinco sprites piden la misma pose, no hacen falta cinco copias de sus gráficos. La primera solicitud puede cargarla y las siguientes encuentran esa misma pose registrada. Después cada sprite la dibuja en su propia posición.&lt;br /&gt;
&lt;br /&gt;
La búsqueda utiliza el ID de la pose. Dos recursos con gráficos visualmente iguales no se consideran necesariamente la misma pose si tienen IDs distintos.&lt;br /&gt;
&lt;br /&gt;
=== Encontrar una pose que ya está cargada ===&lt;br /&gt;
&lt;br /&gt;
El sistema guarda el ID de cada pose registrada, su lugar en VRAM y el momento en que se utilizó por última vez.&lt;br /&gt;
&lt;br /&gt;
Para encontrarla utiliza una tabla hash de 128 entradas. Esto significa que el ID permite calcular dónde comenzar la búsqueda, en lugar de recorrer siempre todas las poses. Después se compara el ID completo para confirmar que es la correcta.&lt;br /&gt;
&lt;br /&gt;
Si la encuentra, actualiza el tiempo de último uso y devuelve su referencia. No vuelve a cargar los gráficos.&lt;br /&gt;
&lt;br /&gt;
=== Cuando la pose todavía no está ===&lt;br /&gt;
&lt;br /&gt;
Para una pose nueva, el sistema consulta las tablas generadas desde el DynamicInfo:&lt;br /&gt;
&lt;br /&gt;
# Obtiene el tamaño de sus gráficos y comprueba el presupuesto del frame.&lt;br /&gt;
# Busca espacio para los bloques de VRAM que necesita.&lt;br /&gt;
# Retira las referencias de las poses que tenga que reemplazar.&lt;br /&gt;
# Registra la nueva pose y el lugar elegido.&lt;br /&gt;
# Prepara las transferencias de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
Si no hay presupuesto o no encuentra espacio adecuado, la solicitud falla. El código que pidió la pose puede intentarlo después.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se reparte VRAM ===&lt;br /&gt;
&lt;br /&gt;
El mapa de espacio distingue zonas reservadas, regiones libres y regiones ocupadas por poses. La reserva se mide en bloques de gráficos de 16×16.&lt;br /&gt;
&lt;br /&gt;
Las configuraciones de espacio deciden qué partes de SP1-SP4 pueden utilizarse. Una región reservada para el jugador, gráficos fijos u otro sistema no puede elegirse para una pose nueva.&lt;br /&gt;
&lt;br /&gt;
El mapa guarda dónde comienza cada región y cuánto ocupa. Puede dividir un espacio libre grande para colocar una pose y dejar el resto disponible. También puede considerar regiones contiguas para reunir el espacio necesario.&lt;br /&gt;
&lt;br /&gt;
=== Qué poses se pueden reemplazar ===&lt;br /&gt;
&lt;br /&gt;
Que una pose no se solicite en un frame no significa que deba sobrescribirse inmediatamente. El sistema protege las utilizadas recientemente y exige al menos dos frames de antigüedad para considerar su espacio.&lt;br /&gt;
&lt;br /&gt;
Entre los espacios que puede utilizar, favorece los que llevan más tiempo sin uso. Si la antigüedad es equivalente, prefiere el espacio suficiente más pequeño, dejando las regiones mayores para otras poses.&lt;br /&gt;
&lt;br /&gt;
Cuando una región reúne varias poses, la protección de todas ellas cuenta. No se puede reemplazar una parte que todavía esté protegida solo porque la pose de al lado sea antigua.&lt;br /&gt;
&lt;br /&gt;
Una pose que dejó de utilizarse puede quedarse en VRAM y continuar registrada. Si vuelve a solicitarse antes de ser reemplazada, se reutiliza sin otra carga.&lt;br /&gt;
&lt;br /&gt;
=== Conservar la pose anterior ===&lt;br /&gt;
&lt;br /&gt;
Si no se puede cargar una pose nueva, las rutinas de sprites pueden seguir utilizando una pose anterior válida. También mantienen su protección para que no se sobrescriba mientras se sigue dibujando.&lt;br /&gt;
&lt;br /&gt;
Esto explica una diferencia importante: una llamada puede devolver una pose utilizable sin haber conseguido todavía la pose nueva.&lt;br /&gt;
&lt;br /&gt;
Si el sprite nunca tuvo una pose válida, no hay una anterior que mostrar. Su código debe comprobar el resultado antes de dibujar.&lt;br /&gt;
&lt;br /&gt;
=== La lógica sigue siendo del sprite ===&lt;br /&gt;
&lt;br /&gt;
La caché no decide cuándo camina, salta o cambia de animación un personaje. El sprite elige la pose, solicita sus gráficos y dibuja con el resultado disponible.&lt;br /&gt;
&lt;br /&gt;
La separación entre short routine y long routine permite evitar parte del trabajo gráfico cuando el sprite no necesita dibujarse. La short routine conserva la lógica correspondiente; la long routine incluye el manejo de paleta, pose y dibujo.&lt;br /&gt;
&lt;br /&gt;
== Efectos de paleta: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
Para cambiar un efecto sin estropear los colores, el sistema tiene que conservar una base. Si cada cambio se aplicara sobre el resultado ya afectado del frame anterior, el color podría ir acumulando modificaciones que no se buscaban.&lt;br /&gt;
&lt;br /&gt;
Por eso se distinguen los colores originales, las versiones preparadas para el cálculo y el resultado que se va a mostrar.&lt;br /&gt;
&lt;br /&gt;
=== Conservar los colores originales ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; guarda la base en formato de SNES. A partir de ella se preparan las representaciones RGB o HSL cuando hacen falta.&lt;br /&gt;
&lt;br /&gt;
RGB separa rojo, verde y azul. HSL separa tono, saturación y luminosidad. Ambas utilizan tres bytes por color; los colores de SNES utilizan dos.&lt;br /&gt;
&lt;br /&gt;
El resultado convertido de nuevo al formato de SNES se guarda en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;, que corresponde al buffer de paletas del juego.&lt;br /&gt;
&lt;br /&gt;
El sistema lleva indicadores para saber qué bases ya tiene preparadas. Si se pasa de un efecto RGB a uno HSL, no debe tomar los colores afectados como si fueran los originales.&lt;br /&gt;
&lt;br /&gt;
=== Preparar la base cuando hace falta ===&lt;br /&gt;
&lt;br /&gt;
Una paleta sin base registrada puede obtener sus colores del buffer del juego. Una carga explícita, como &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, proporciona los colores que deben utilizarse como base.&lt;br /&gt;
&lt;br /&gt;
La conversión a RGB o HSL se hace cuando se necesita. Después puede reutilizarse mientras no cambien los colores de origen.&lt;br /&gt;
&lt;br /&gt;
Cuando llegan colores nuevos, las conversiones y efectos anteriores dejan de servir. Las llamadas correspondientes de carga actualizan la base y borran los indicadores que deben volver a calcularse.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto ===&lt;br /&gt;
&lt;br /&gt;
El ID del efecto permite leer su tipo, valores y ratios en las tablas preparadas al instalar.&lt;br /&gt;
&lt;br /&gt;
Los canales utilizan valores de 0 a 31. Los ratios van de 0 a 127: 0 conserva el origen y 127 aplica por completo el cambio elegido.&lt;br /&gt;
&lt;br /&gt;
Un efecto puede modificar un canal, varios canales o mezclar los colores con los de otra paleta. Las transiciones utilizan los destinos RGB o HSL que ya se prepararon durante la instalación.&lt;br /&gt;
&lt;br /&gt;
Los cálculos se hacen fuera de NMI. La parte de NMI se encarga de copiar los colores resultantes, no de calcular cada efecto durante la transferencia.&lt;br /&gt;
&lt;br /&gt;
=== El efecto global ===&lt;br /&gt;
&lt;br /&gt;
El juego selecciona un ID global y elige mediante máscaras qué paletas deben recibirlo. El color fijo y el color 0,0 tienen sus propios indicadores.&lt;br /&gt;
&lt;br /&gt;
El administrador comprueba si cada paleta necesita una actualización. Si la base no cambió y sigue siendo válido el resultado del mismo efecto, puede reutilizarlo.&lt;br /&gt;
&lt;br /&gt;
Al cambiar el ID global, los resultados del efecto anterior dejan de servir, pero las bases RGB y HSL pueden seguir siendo válidas si sus colores de origen no cambiaron.&lt;br /&gt;
&lt;br /&gt;
Poner el ID global en 0 permite volver a los colores de base. Para restaurarlos, el sistema todavía tiene que procesar las paletas afectadas; no basta con dejar de trabajar sobre ellas.&lt;br /&gt;
&lt;br /&gt;
=== Combinar un efecto local con el global ===&lt;br /&gt;
&lt;br /&gt;
Un sprite puede necesitar un cambio de color propio y, además, recibir el efecto general del nivel. Por ejemplo, puede cambiar de tono y después oscurecerse junto con el resto de la pantalla.&lt;br /&gt;
&lt;br /&gt;
Las llamadas de concatenación permiten preparar el resultado local como base del efecto global. La variante RGB se utiliza con efectos RGB; la HSL, con efectos HSL.&lt;br /&gt;
&lt;br /&gt;
No hay que mostrar primero el resultado local sin el efecto global. Se prepara la base para que la carga final ya contenga la combinación correspondiente.&lt;br /&gt;
&lt;br /&gt;
Los recursos que comparten una paleta de CGRAM también comparten sus colores. Dos sprites que necesiten efectos locales diferentes deben disponer de destinos adecuados para mostrar ambos resultados.&lt;br /&gt;
&lt;br /&gt;
=== Cargar el resultado ===&lt;br /&gt;
&lt;br /&gt;
Cuando los colores están preparados, se solicita su transferencia a CGRAM. Esa carga también puede quedar pendiente si no se acepta por el presupuesto.&lt;br /&gt;
&lt;br /&gt;
Preparar una base o calcular un efecto no significa que ya esté en pantalla. El administrador confirma sus cambios de estado según el resultado de la carga y puede volver a intentar una actualización pendiente.&lt;br /&gt;
&lt;br /&gt;
Cuando corresponde, se mantiene un resultado anterior utilizable hasta poder sustituirlo. Esto permite distinguir una paleta que todavía está cambiando de una que nunca tuvo colores disponibles para mostrarse.&lt;br /&gt;
&lt;br /&gt;
Cargar directamente los colores originales antes del efecto podría hacer que se vieran un frame sin él. Por eso las cargas destinadas al efecto global preparan la base y dejan que se muestre el resultado ya procesado.&lt;br /&gt;
&lt;br /&gt;
== Cómo trabajan juntos ==&lt;br /&gt;
&lt;br /&gt;
Un sprite dinámico utiliza varias de estas partes durante el mismo frame. Su lógica elige una pose y una paleta; la asignación encuentra colores utilizables; la caché encuentra o prepara los gráficos; y el dibujo coloca sus piezas.&lt;br /&gt;
&lt;br /&gt;
Después, el administrador de efectos prepara los cambios globales que hagan falta y NMI realiza las transferencias solicitadas.&lt;br /&gt;
&lt;br /&gt;
Compartir gráficos, compartir una paleta y compartir una rutina de dibujo son tres cosas distintas. Dynamic Xtreme puede aprovechar cada una sin obligar a que los recursos compartan también las demás.&lt;br /&gt;
&lt;br /&gt;
== Lecturas relacionadas ==&lt;br /&gt;
&lt;br /&gt;
* [[es/Dynamic_Xtreme|Artículo principal]]: funcionalidades y compatibilidad.&lt;br /&gt;
* [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_sprite_creation_guide|Creación de sprites dinámicos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_UberASM_guide|Dynamic Xtreme con UberASM]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_ASM_API|API ASM]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21368</id>
		<title>es/Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21368"/>
		<updated>2026-10-25T01:19:20Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo funciona Dynamic Xtreme, desde la preparación de los recursos al instalarlo hasta la carga y el dibujo de una pose durante el juego.&lt;br /&gt;
&lt;br /&gt;
== Qué prepara la instalación ==&lt;br /&gt;
&lt;br /&gt;
Antes de que un sprite pueda usar sus gráficos o una paleta, Dynamic Xtreme tiene que guardarlos en la ROM y preparar la información para encontrarlos. Lo mismo ocurre con cualquier otro recurso dinámico que hayas añadido.&lt;br /&gt;
&lt;br /&gt;
Para hacerlo, la herramienta lee los DynamicInfo, DrawInfo y PaletteEffect. Cada archivo aporta una parte distinta: qué recursos se van a cargar, cómo se dibujan las poses y qué cambios de color se pueden aplicar.&lt;br /&gt;
&lt;br /&gt;
El resultado no es solo una copia de los archivos originales. La instalación prepara los datos, genera tablas y rutinas, y publica sus nombres en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Así, durante el juego basta con pedir una pose o un efecto por su ID; no hay que volver a leer ni interpretar los archivos de texto.&lt;br /&gt;
&lt;br /&gt;
=== DynamicInfo: recursos y datos de carga ===&lt;br /&gt;
&lt;br /&gt;
Un DynamicInfo reúne los gráficos de poses, las paletas y los recursos generales que necesita un sprite u otro código. Si incluye gráficos de poses dinámicas, la herramienta los organiza para que puedan cargarse con la distribución de tiles que espera el sistema.&lt;br /&gt;
&lt;br /&gt;
Por cada pose guarda varios datos en tablas separadas. Todas mantienen el mismo orden: la entrada de una pose en una tabla corresponde a esa misma pose en las demás.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSize&amp;lt;/code&amp;gt; || El tamaño de los gráficos de cada pose, en bytes. Se utiliza para comprobar si su carga cabe en el presupuesto del frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Pose16x16Blocks&amp;lt;/code&amp;gt; || Cuántos bloques de 16×16 hay que reservar en VRAM para la pose. No siempre coincide exactamente con los bytes que se copian, porque una pieza incompleta también puede necesitar un bloque de espacio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResource&amp;lt;/code&amp;gt; || La dirección de los gráficos de cada pose en ROM. Incluye el banco, de modo que el código de carga pueda encontrar su origen completo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseResourceSizePerLine&amp;lt;/code&amp;gt; || Dos tamaños por pose, correspondientes a los dos tramos en que pueden dividirse sus gráficos. La rutina de carga utiliza esos tamaños para repartirlos correctamente en VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PoseSecondLineOffset&amp;lt;/code&amp;gt; || El desplazamiento en VRAM desde el comienzo del primer tramo hasta el comienzo del segundo. Permite colocar el segundo tramo donde corresponde, aunque el primero termine con una fila incompleta.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas tablas describen todas las poses instaladas, no solo las que están en pantalla. Más adelante, la caché guarda por separado cuáles están cargadas y dónde quedaron.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si se solicita una pose que todavía no está en VRAM, el sistema consulta su tamaño, busca espacio para sus bloques y utiliza la dirección y los datos de sus tramos para preparar la carga.&lt;br /&gt;
&lt;br /&gt;
==== Tablas de paletas ====&lt;br /&gt;
&lt;br /&gt;
Las paletas declaradas en los DynamicInfo se reúnen en &amp;lt;code&amp;gt;PaletteTable&amp;lt;/code&amp;gt;. Esta tiene dos partes:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;PaletteTable.IDs&amp;lt;/code&amp;gt; guarda el ID de cada paleta.&lt;br /&gt;
* &amp;lt;code&amp;gt;PaletteTable.Addresses&amp;lt;/code&amp;gt; guarda dónde están sus colores en ROM.&lt;br /&gt;
&lt;br /&gt;
Las dos listas siguen el orden de las paletas de los DynamicInfo. El define de offset de cada DynamicInfo indica dónde comienza su lista dentro de ellas. Al elegir una versión, el sistema suma ese índice al offset y obtiene tanto el ID como la dirección de los colores elegidos.&lt;br /&gt;
&lt;br /&gt;
El ID permite reconocer y compartir una paleta; la dirección permite cargarla. No son el número de paleta de pantalla: una misma paleta instalada puede terminar, por ejemplo, en la paleta 9 o en la C según la asignación.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y defines ====&lt;br /&gt;
&lt;br /&gt;
Los archivos declarados en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; no necesitan seguir el formato de una pose o una paleta. Pueden contener gráficos para animaciones, datos para un jugador u otros datos que tu código sepa utilizar.&lt;br /&gt;
&lt;br /&gt;
La herramienta los inserta en ROM y genera sus defines de ID, dirección y tamaño. A diferencia de las poses dinámicas, no les asigna automáticamente un lugar de VRAM ni decide cuándo deben cargarse: eso queda a cargo del código que los utiliza.&lt;br /&gt;
&lt;br /&gt;
=== DrawInfo: datos y rutinas de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El DrawInfo describe cómo está formada una pose: qué tiles tiene, dónde se coloca cada uno, qué tamaño utiliza y cómo cambia al voltearse.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, Dynamic Xtreme prepara esos datos y elige una rutina de dibujo adecuada. Varias poses pueden compartir una rutina si necesitan el mismo tipo de tratamiento. Compartir la rutina no significa que compartan también sus gráficos o su ID.&lt;br /&gt;
&lt;br /&gt;
La relación entre una pose y su dibujo se guarda en estas tablas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tabla !! Qué guarda y para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TableOffset&amp;lt;/code&amp;gt; || Dónde comienzan los datos de la pose dentro de las tablas de su rutina de dibujo. Así se localizan sus tiles y desplazamientos sin recorrer las poses anteriores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NumberOfTilesMinus1&amp;lt;/code&amp;gt; || La cantidad de tiles de la pose menos uno. Una pose de cuatro tiles guarda 3; la rutina utiliza ese valor para recorrer sus piezas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutineIDs&amp;lt;/code&amp;gt; || Qué rutina de dibujo utiliza cada pose. Las poses con características compatibles pueden apuntar al mismo ID de rutina.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GraphicRoutine&amp;lt;/code&amp;gt; || Las direcciones de las rutinas de dibujo. El ID de rutina permite encontrar aquí el código que debe ejecutarse.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada rutina tiene, además, las tablas que necesitan sus poses:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos !! Qué describen&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Tiles&amp;lt;/code&amp;gt; || Los números de tile que forman la pose.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Properties&amp;lt;/code&amp;gt; || Las propiedades de cada pieza, como los volteos y su prioridad respecto a las capas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;XDisplacements&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;YDisplacements&amp;lt;/code&amp;gt; || La posición de cada tile respecto al punto de origen de la pose.&lt;br /&gt;
|-&lt;br /&gt;
| Tablas de desplazamientos para los volteos || Las posiciones que deben utilizarse al voltear la pose cuando necesita una distribución distinta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Sizes&amp;lt;/code&amp;gt; || El tamaño de cada tile: 8×8 o 16×16.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
No todas estas tablas tienen que aparecer en todas las rutinas. Si un dato es igual para todas las piezas o puede obtenerse de un valor común, la herramienta puede generar una rutina que lo utilice directamente.&lt;br /&gt;
&lt;br /&gt;
Por eso se hace parte del trabajo al instalar: el juego recibe una rutina preparada para esos datos, en lugar de tener que interpretar todas las opciones de un DrawInfo cada vez que dibuja.&lt;br /&gt;
&lt;br /&gt;
=== PaletteEffect: datos de los efectos ===&lt;br /&gt;
&lt;br /&gt;
Un archivo PaletteEffect contiene una lista de cambios de color. La instalación les asigna IDs y guarda sus datos en &amp;lt;code&amp;gt;PaletteEffectsTable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Como en las tablas de poses, los datos de cada efecto mantienen la misma posición en las distintas listas. Los IDs de efectos comienzan en 1; el ID 0 se utiliza para indicar que no hay efecto global.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parte de la tabla !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt; || La cantidad de efectos instalados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Types&amp;lt;/code&amp;gt; || El tipo de cada efecto, por ejemplo &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt;. Indica qué cálculo debe realizarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Value1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Value2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Value3&amp;lt;/code&amp;gt; || Los valores de los canales que utiliza el efecto. En una transición, estos tres bytes guardan la dirección de la paleta de destino, no valores de canales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Ratio1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio3&amp;lt;/code&amp;gt; || Cuánto se aplica el cambio en cada componente. Van de 0 a 127.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Si el efecto es una transición hacia otra paleta, la herramienta también prepara esa paleta. Convierte sus colores al formato RGB o HSL que necesita la transición y los guarda en ROM. Durante el juego se puede utilizar ese destino sin tener que convertirlo de nuevo en cada llamada.&lt;br /&gt;
&lt;br /&gt;
Estas paletas de transición son distintas de las paletas normales que se cargan a CGRAM: contienen tres componentes por color y se utilizan para calcular el efecto.&lt;br /&gt;
&lt;br /&gt;
=== Cómo encuentra el código los recursos instalados ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; publica los IDs, direcciones, tamaños y offsets que necesitan los recursos. Por ejemplo, &amp;lt;code&amp;gt;!DynamicPoseIDMySpriteIdle&amp;lt;/code&amp;gt; identifica una pose y &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; identifica el primer efecto de un archivo.&lt;br /&gt;
&lt;br /&gt;
Los nombres se normalizan en PascalCase: se eliminan separadores como espacios, guiones y guiones bajos, y se pone en mayúscula la inicial de cada palabra. &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, por ejemplo, pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También se genera &amp;lt;code&amp;gt;BufferTable&amp;lt;/code&amp;gt;, que guarda las direcciones de los bloques donde se insertaron los recursos. La herramienta utiliza esa información para localizar los datos de una instalación anterior al reinstalar.&lt;br /&gt;
&lt;br /&gt;
Una reinstalación puede cambiar IDs y direcciones. Por eso hay que volver a insertar los sprites, bloques y códigos UberASM que utilizan los defines generados.&lt;br /&gt;
&lt;br /&gt;
== El trabajo de cada frame ==&lt;br /&gt;
&lt;br /&gt;
Durante el juego hay dos momentos que conviene distinguir: decidir qué se necesita mostrar y copiar los datos a la memoria de video.&lt;br /&gt;
&lt;br /&gt;
Un sprite puede pedir una pose mientras ejecuta su código. Dynamic Xtreme busca sus gráficos, comprueba si hay espacio y prepara la carga. La copia a VRAM se realiza después, durante NMI.&lt;br /&gt;
&lt;br /&gt;
Lo mismo sucede con las paletas: elegir colores o calcular un efecto no significa que ya se hayan enviado a pantalla.&lt;br /&gt;
&lt;br /&gt;
El recorrido general es:&lt;br /&gt;
&lt;br /&gt;
# NMI realiza las cargas que habían quedado preparadas y vacía las listas para recibir nuevas solicitudes.&lt;br /&gt;
# El modo de juego ejecuta su lógica: jugador, sprites, animaciones y otros códigos.&lt;br /&gt;
# Esos códigos solicitan los gráficos y colores que necesitan y preparan el dibujo.&lt;br /&gt;
# La parte de paletas del game mode mantiene sus asignaciones y procesa los efectos globales pendientes.&lt;br /&gt;
# La siguiente NMI realiza las nuevas transferencias.&lt;br /&gt;
&lt;br /&gt;
=== Qué hace NMI ===&lt;br /&gt;
&lt;br /&gt;
SNES puede generar la interrupción NMI al comenzar VBlank, el intervalo que sigue al dibujo de la parte visible de la pantalla. El juego aprovecha ese tiempo para actualizar gráficos, colores y otros datos de video.&lt;br /&gt;
&lt;br /&gt;
Ese intervalo es corto y Dynamic Xtreme no es lo único que lo utiliza. Todavía tienen que realizarse las tareas normales de pantalla del juego.&lt;br /&gt;
&lt;br /&gt;
Para aprovecharlo, Dynamic Xtreme deja preparado el trabajo antes de llegar a NMI. Guarda las transferencias en listas de RAM: cada entrada indica el origen de los datos, su tamaño y el destino.&lt;br /&gt;
&lt;br /&gt;
Durante NMI, el parche recorre esas listas y utiliza DMA, el mecanismo de la consola para copiar los datos. Las transferencias de gráficos van a VRAM; las de colores, a CGRAM.&lt;br /&gt;
&lt;br /&gt;
Después vacía las listas. Esto no borra lo que acaba de cargar: los gráficos y colores siguen allí hasta que otro código los cambie.&lt;br /&gt;
&lt;br /&gt;
Si los datos de origen están en RAM, tienen que conservarse hasta que se ejecute la transferencia. Cambiarlos antes puede hacer que se copie algo distinto de lo solicitado.&lt;br /&gt;
&lt;br /&gt;
==== Las listas de transferencias ====&lt;br /&gt;
&lt;br /&gt;
La lista de VRAM utiliza 0 cuando no tiene entradas. La de CGRAM utiliza &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, porque guarda el índice de la última entrada en lugar de guardar directamente su cantidad.&lt;br /&gt;
&lt;br /&gt;
Ambas se recorren desde la última entrada hacia la primera. Si dos códigos quieren escribir sobre el mismo destino, deben ponerse de acuerdo; no basta con asumir que la última solicitud será la que termine viéndose.&lt;br /&gt;
&lt;br /&gt;
En los game modes permitidos, la rutina de NMI también reinicia el contador de datos del nuevo frame y actualiza los relojes de Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
==== Cuánto se puede cargar ====&lt;br /&gt;
&lt;br /&gt;
Cada carga ocupa parte del tiempo disponible. Para evitar pedir más de lo razonable, el sistema suma los bytes solicitados en &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; y los compara con &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El límite predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, es decir, 2048 bytes. Sirve para controlar la cantidad de datos; no es una medida exacta del tiempo que tardará cualquier combinación de transferencias.&lt;br /&gt;
&lt;br /&gt;
Si una carga normal no cabe, se rechaza. El código que la necesita puede conservar lo anterior y volver a pedirla después. Una solicitud rechazada no queda guardada automáticamente para otro frame.&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; omiten esa comprobación, pero también suman sus bytes al contador. Permiten dar prioridad a ciertas cargas; no aumentan el tiempo que tiene la consola.&lt;br /&gt;
&lt;br /&gt;
=== Qué hace la parte de game mode ===&lt;br /&gt;
&lt;br /&gt;
SMW separa sus estados en game modes: carga del nivel, juego dentro del nivel, transiciones y otras pantallas. El número del modo actual está en &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme consulta una tabla para decidir en cuáles debe funcionar. En los modos no permitidos reinicializa su estado, de modo que no conserve asignaciones de una pantalla que ya dejó atrás.&lt;br /&gt;
&lt;br /&gt;
Esa inicialización prepara listas, contadores, marcas de paletas y los demás datos de las funcionalidades habilitadas. Puede repetirse mientras el juego permanezca en un modo no permitido; no ocurre solamente al detectar un cambio de modo.&lt;br /&gt;
&lt;br /&gt;
La parte de game mode también reúne trabajo que no necesita hacerse durante NMI. Según las opciones instaladas, incluye el control, parte de las actualizaciones de VRAM y el mantenimiento de paletas.&lt;br /&gt;
&lt;br /&gt;
Después de ejecutar el modo de juego, la parte de paletas limpia las marcas de actualización del frame y reduce los temporizadores de protección cuando corresponde. También calcula los efectos globales pendientes.&lt;br /&gt;
&lt;br /&gt;
Algunas llamadas de sprites tienen una lista de modos permitidos más limitada que la general. Que el sistema esté activo en una pantalla no significa que todas esas llamadas deban cargar poses nuevas allí.&lt;br /&gt;
&lt;br /&gt;
==== Los dos relojes ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; cuenta los frames en los que se ejecuta la rutina correspondiente de Dynamic Xtreme. Sigue avanzando durante la pausa y permite medir cuánto lleva una pose sin utilizarse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; se detiene durante la pausa y cuando se congela la acción. Es útil para animaciones que deben detenerse junto con el juego.&lt;br /&gt;
&lt;br /&gt;
Son dos necesidades distintas. Una animación puede quedarse quieta durante la pausa y, al mismo tiempo, una pose que nadie solicita puede acumular tiempo sin uso.&lt;br /&gt;
&lt;br /&gt;
== Carga de gráficos: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; permite programar cargas de gráficos a VRAM. Lo utilizan las animaciones de tiles, las poses dinámicas y las rutinas de gráficos del jugador y Yoshi.&lt;br /&gt;
&lt;br /&gt;
La idea básica es sencilla: el código indica qué datos quiere copiar y dónde quiere ponerlos. Si la solicitud se acepta, se añade a la lista y sus bytes cuentan para el presupuesto del frame.&lt;br /&gt;
&lt;br /&gt;
Esta parte no elige la siguiente imagen de una animación ni reparte por sí sola el espacio entre sprites. Esas decisiones las toma el código que solicita la carga o el administrador de poses dinámicas.&lt;br /&gt;
&lt;br /&gt;
=== Animaciones en un destino fijo ===&lt;br /&gt;
&lt;br /&gt;
Una animación puede cambiar los gráficos de unos tiles sin cambiar sus números. Para ello copia cada imagen al mismo lugar de VRAM.&lt;br /&gt;
&lt;br /&gt;
El código de animación elige la imagen y pide su carga. Si no se acepta, puede mantener la imagen anterior y esperar al siguiente intento.&lt;br /&gt;
&lt;br /&gt;
Así la animación tiene en cuenta las demás cargas del frame en lugar de copiar sus gráficos sin importar cuánto trabajo se había pedido.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se colocan los gráficos de una pose ===&lt;br /&gt;
&lt;br /&gt;
Los gráficos de una pose pueden necesitar varias transferencias para quedar en las filas de tiles correctas. No siempre se pueden copiar como un bloque seguido a partir de una única dirección de VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; utiliza los tamaños y desplazamientos preparados al instalar. Recibe el lugar elegido para la pose, calcula los destinos y añade las transferencias necesarias.&lt;br /&gt;
&lt;br /&gt;
Encontrar ese lugar y decidir si puede utilizarse es el trabajo de la caché, que se explica más adelante. La rutina de carga se ocupa de colocar los gráficos en él.&lt;br /&gt;
&lt;br /&gt;
== Carga y asignación de paletas: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
Una paleta instalada es un conjunto de colores guardados en ROM. Una paleta de pantalla es el lugar de CGRAM donde se colocan esos colores para dibujar.&lt;br /&gt;
&lt;br /&gt;
Un sprite puede pedir su paleta azul sin exigir que siempre ocupe la paleta 9. La asignación automática puede encontrarle un destino entre las paletas de sprites que tenga permitidas.&lt;br /&gt;
&lt;br /&gt;
=== Cargar colores ===&lt;br /&gt;
&lt;br /&gt;
La copia a CGRAM se prepara de forma parecida a una carga de gráficos: necesita un origen, un primer color de destino y una cantidad de bytes. Cada color de SNES ocupa dos bytes.&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; también actualizan las copias de colores del juego. Esto es importante porque SMW puede volver a utilizarlas, por ejemplo durante la animación de victoria del goal. Cambiar solo CGRAM dejaría esas copias con los colores anteriores.&lt;br /&gt;
&lt;br /&gt;
Cuando la paleta debe recibir un efecto global, se guardan primero sus colores originales. El sistema calcula el efecto sobre ellos y carga el resultado, sin mostrar antes una versión sin efecto.&lt;br /&gt;
&lt;br /&gt;
=== Encontrar una paleta disponible ===&lt;br /&gt;
&lt;br /&gt;
Para asignar un destino, el sistema busca primero una paleta con el mismo ID y una condición de efecto compatible. Si ya existe, puede compartirla en lugar de cargar otra copia.&lt;br /&gt;
&lt;br /&gt;
Si no la encuentra, busca una entrada libre. Si tampoco hay una libre, puede reemplazar una que haya dejado de estar protegida.&lt;br /&gt;
&lt;br /&gt;
Cada entrada guarda qué ID utiliza y un temporizador de protección. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; significa que está libre; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; significa que está reservada y que la asignación automática no debe ocuparla.&lt;br /&gt;
&lt;br /&gt;
Mientras un recurso utiliza su paleta, mantiene ese temporizador en 2. Así otro recurso no la reemplaza entre un frame y el siguiente.&lt;br /&gt;
&lt;br /&gt;
Cuando el temporizador llega a cero, los colores no desaparecen. Si alguien vuelve a pedir la misma paleta antes de que se reemplace, todavía puede aprovechar esa asignación.&lt;br /&gt;
&lt;br /&gt;
=== Asignación manual y versión ===&lt;br /&gt;
&lt;br /&gt;
En modo manual, el código elige el destino. Puede cargar allí sus colores o utilizar los que ya estaban preparados en el nivel. Si dos recursos eligen ese destino con colores distintos, tendrán que coordinarse para no sobrescribirse.&lt;br /&gt;
&lt;br /&gt;
En las rutinas de sprites, la versión elige una entrada de la lista de paletas del DynamicInfo. La última versión procesada permite saber si esa selección cambió.&lt;br /&gt;
&lt;br /&gt;
Mantener una paleta en uso no implica volver a cargarla cada frame. Si sigue siendo válida, lo que se mantiene es su protección.&lt;br /&gt;
&lt;br /&gt;
== Dibujo de poses: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
Tener los gráficos en VRAM no hace que un sprite aparezca por sí solo. También hay que indicar qué tiles lo forman, dónde van y con qué propiedades se muestran.&lt;br /&gt;
&lt;br /&gt;
Ese es el trabajo del dibujo. El sistema toma la pose del DrawInfo y prepara sus piezas en OAM, la memoria que utiliza la consola para colocar los sprites en pantalla.&lt;br /&gt;
&lt;br /&gt;
=== De los datos a las piezas visibles ===&lt;br /&gt;
&lt;br /&gt;
La rutina suma a la posición del sprite los desplazamientos de cada tile. También aplica los volteos y combina la paleta y las demás propiedades necesarias.&lt;br /&gt;
&lt;br /&gt;
En una pose dinámica, ajusta los tiles al lugar donde quedaron cargados sus gráficos. En una pose estática, utiliza sus posiciones fijas. Si el dibujo toma un tile común desde &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, el código debe preparar ese valor.&lt;br /&gt;
&lt;br /&gt;
Antes de añadir una pieza, se comprueba si puede verse en pantalla y si queda espacio de OAM. Tener una pose cargada no garantiza que puedan dibujarse todas sus piezas.&lt;br /&gt;
&lt;br /&gt;
=== Prioridad de dibujo ===&lt;br /&gt;
&lt;br /&gt;
El sistema organiza las piezas según la prioridad de dibujo. En LoROM lleva su propio control de las entradas disponibles; en SA-1 utiliza la integración con MaxTile.&lt;br /&gt;
&lt;br /&gt;
Esta prioridad decide el orden entre piezas de sprites. No es lo mismo que la propiedad que determina si un tile queda delante o detrás de las capas del nivel.&lt;br /&gt;
&lt;br /&gt;
La organización de OAM ayuda a utilizar su espacio, pero no elimina el límite de sprites y tiles que SNES puede mostrar en una misma línea.&lt;br /&gt;
&lt;br /&gt;
== Jugador y Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
El jugador original tiene rutinas propias para elegir y cargar las piezas de sus poses. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; permite integrar ese trabajo con las cargas de Dynamic Xtreme y cambiar el origen de sus gráficos y paletas.&lt;br /&gt;
&lt;br /&gt;
Con el formato original, el juego sigue eligiendo las piezas de la pose. La rutina obtiene sus direcciones desde el origen configurado y compara esas direcciones con las anteriores para cargar las que hayan cambiado.&lt;br /&gt;
&lt;br /&gt;
Estas cargas utilizan transferencias forzadas y sus bytes también cuentan para las solicitudes normales posteriores. Así conservan su prioridad sin quedar fuera de la contabilidad del sistema.&lt;br /&gt;
&lt;br /&gt;
La paleta del jugador tiene un tratamiento especial: combina colores y selecciones del propio juego con el origen personalizado. No funciona simplemente como sustituir una paleta completa de un sprite cualquiera.&lt;br /&gt;
&lt;br /&gt;
El soporte para jugadores personalizados permite que otros sistemas administren de otra forma sus poses y dibujo. No convierte automáticamente cualquier spritesheet al formato del jugador original.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
Yoshi también carga sus gráficos por piezas. &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; permite cambiar su origen manteniendo la organización que esperan sus rutinas.&lt;br /&gt;
&lt;br /&gt;
El código calcula qué partes necesita y prepara sus cargas a los destinos correspondientes de VRAM. Como las del jugador, estas cargas tienen un tratamiento prioritario.&lt;br /&gt;
&lt;br /&gt;
Esta opción necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad. No permite evitar un conflicto del sistema del jugador habilitando únicamente las funciones de Yoshi.&lt;br /&gt;
&lt;br /&gt;
== Memoria y optimizaciones ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW mantiene en RAM gráficos originales del jugador, Yoshi y ciertas animaciones. En ROMs sin SA-1, esta opción adapta las cargas para leer esos datos desde ROM.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme aprovecha la RAM recuperada para sus variables internas. No es un espacio que quede libre para que cualquier otro código escriba encima.&lt;br /&gt;
&lt;br /&gt;
SA-1 utiliza otras direcciones y desactiva esta opción. Los rangos están en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
Esta opción mueve el procesamiento del control desde NMI a la parte de game mode. El objetivo es dejar más tiempo para las actualizaciones de pantalla, no añadir un frame de retraso ni cambiar los botones que recibe el juego.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
El color fijo se utiliza en las mezclas de color de la consola. Para actualizarlo, el juego prepara sus componentes y los envía al registro correspondiente.&lt;br /&gt;
&lt;br /&gt;
La optimización reemplaza esa preparación por una secuencia más corta. El color sigue enviándose a la consola, pero necesita menos trabajo durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic utiliza listas llamadas stripe images para actualizar partes de los mapas de tiles. Esas listas incluyen tanto los datos como la información sobre sus destinos.&lt;br /&gt;
&lt;br /&gt;
La versión integrada de la optimización de Kevin prepara fuera de NMI parte del ajuste de esos destinos. Así deja menos trabajo de preparación para el momento de la transferencia.&lt;br /&gt;
&lt;br /&gt;
Esta opción sustituye el uso del parche original por separado. Además, no debe desinstalarse después de instalarla; hay que tenerlo en cuenta antes de activarla.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
La barra de estado original actualiza zonas concretas de VRAM. Esta opción prepara sus transferencias de forma más directa, reduciendo la configuración de DMA que necesita hacer durante NMI.&lt;br /&gt;
&lt;br /&gt;
No añade una barra nueva. Modifica la actualización de la original y, por eso, entra en conflicto con recursos que la reemplazan, modifican o eliminan.&lt;br /&gt;
&lt;br /&gt;
== Sprites dinámicos: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
El sistema utiliza el espacio disponible de VRAM como una caché de poses. Conserva las que ya cargó para reutilizarlas y busca cuáles puede reemplazar cuando hace falta espacio.&lt;br /&gt;
&lt;br /&gt;
En lugar de darle a cada sprite un espacio fijo para todos sus gráficos, permite que pida la pose que necesita en ese momento.&lt;br /&gt;
&lt;br /&gt;
=== Una pose para varias entidades ===&lt;br /&gt;
&lt;br /&gt;
Si cinco sprites piden la misma pose, no hacen falta cinco copias de sus gráficos. La primera solicitud puede cargarla y las siguientes encuentran esa misma pose registrada. Después cada sprite la dibuja en su propia posición.&lt;br /&gt;
&lt;br /&gt;
La búsqueda utiliza el ID de la pose. Dos recursos con gráficos visualmente iguales no se consideran necesariamente la misma pose si tienen IDs distintos.&lt;br /&gt;
&lt;br /&gt;
=== Encontrar una pose que ya está cargada ===&lt;br /&gt;
&lt;br /&gt;
El sistema guarda el ID de cada pose registrada, su lugar en VRAM y el momento en que se utilizó por última vez.&lt;br /&gt;
&lt;br /&gt;
Para encontrarla utiliza una tabla hash de 128 entradas. Esto significa que el ID permite calcular dónde comenzar la búsqueda, en lugar de recorrer siempre todas las poses. Después se compara el ID completo para confirmar que es la correcta.&lt;br /&gt;
&lt;br /&gt;
Si la encuentra, actualiza el tiempo de último uso y devuelve su referencia. No vuelve a cargar los gráficos.&lt;br /&gt;
&lt;br /&gt;
=== Cuando la pose todavía no está ===&lt;br /&gt;
&lt;br /&gt;
Para una pose nueva, el sistema consulta las tablas generadas desde el DynamicInfo:&lt;br /&gt;
&lt;br /&gt;
# Obtiene el tamaño de sus gráficos y comprueba el presupuesto del frame.&lt;br /&gt;
# Busca espacio para los bloques de VRAM que necesita.&lt;br /&gt;
# Retira las referencias de las poses que tenga que reemplazar.&lt;br /&gt;
# Registra la nueva pose y el lugar elegido.&lt;br /&gt;
# Prepara las transferencias de sus gráficos.&lt;br /&gt;
&lt;br /&gt;
Si no hay presupuesto o no encuentra espacio adecuado, la solicitud falla. El código que pidió la pose puede intentarlo después.&lt;br /&gt;
&lt;br /&gt;
=== Cómo se reparte VRAM ===&lt;br /&gt;
&lt;br /&gt;
El mapa de espacio distingue zonas reservadas, regiones libres y regiones ocupadas por poses. La reserva se mide en bloques de gráficos de 16×16.&lt;br /&gt;
&lt;br /&gt;
Las configuraciones de espacio deciden qué partes de SP1-SP4 pueden utilizarse. Una región reservada para el jugador, gráficos fijos u otro sistema no puede elegirse para una pose nueva.&lt;br /&gt;
&lt;br /&gt;
El mapa guarda dónde comienza cada región y cuánto ocupa. Puede dividir un espacio libre grande para colocar una pose y dejar el resto disponible. También puede considerar regiones contiguas para reunir el espacio necesario.&lt;br /&gt;
&lt;br /&gt;
=== Qué poses se pueden reemplazar ===&lt;br /&gt;
&lt;br /&gt;
Que una pose no se solicite en un frame no significa que deba sobrescribirse inmediatamente. El sistema protege las utilizadas recientemente y exige al menos dos frames de antigüedad para considerar su espacio.&lt;br /&gt;
&lt;br /&gt;
Entre los espacios que puede utilizar, favorece los que llevan más tiempo sin uso. Si la antigüedad es equivalente, prefiere el espacio suficiente más pequeño, dejando las regiones mayores para otras poses.&lt;br /&gt;
&lt;br /&gt;
Cuando una región reúne varias poses, la protección de todas ellas cuenta. No se puede reemplazar una parte que todavía esté protegida solo porque la pose de al lado sea antigua.&lt;br /&gt;
&lt;br /&gt;
Una pose que dejó de utilizarse puede quedarse en VRAM y continuar registrada. Si vuelve a solicitarse antes de ser reemplazada, se reutiliza sin otra carga.&lt;br /&gt;
&lt;br /&gt;
=== Conservar la pose anterior ===&lt;br /&gt;
&lt;br /&gt;
Si no se puede cargar una pose nueva, las rutinas de sprites pueden seguir utilizando una pose anterior válida. También mantienen su protección para que no se sobrescriba mientras se sigue dibujando.&lt;br /&gt;
&lt;br /&gt;
Esto explica una diferencia importante: una llamada puede devolver una pose utilizable sin haber conseguido todavía la pose nueva.&lt;br /&gt;
&lt;br /&gt;
Si el sprite nunca tuvo una pose válida, no hay una anterior que mostrar. Su código debe comprobar el resultado antes de dibujar.&lt;br /&gt;
&lt;br /&gt;
=== La lógica sigue siendo del sprite ===&lt;br /&gt;
&lt;br /&gt;
La caché no decide cuándo camina, salta o cambia de animación un personaje. El sprite elige la pose, solicita sus gráficos y dibuja con el resultado disponible.&lt;br /&gt;
&lt;br /&gt;
La separación entre short routine y long routine permite evitar parte del trabajo gráfico cuando el sprite no necesita dibujarse. La short routine conserva la lógica correspondiente; la long routine incluye el manejo de paleta, pose y dibujo.&lt;br /&gt;
&lt;br /&gt;
== Efectos de paleta: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
Para cambiar un efecto sin estropear los colores, el sistema tiene que conservar una base. Si cada cambio se aplicara sobre el resultado ya afectado del frame anterior, el color podría ir acumulando modificaciones que no se buscaban.&lt;br /&gt;
&lt;br /&gt;
Por eso se distinguen los colores originales, las versiones preparadas para el cálculo y el resultado que se va a mostrar.&lt;br /&gt;
&lt;br /&gt;
=== Conservar los colores originales ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; guarda la base en formato de SNES. A partir de ella se preparan las representaciones RGB o HSL cuando hacen falta.&lt;br /&gt;
&lt;br /&gt;
RGB separa rojo, verde y azul. HSL separa tono, saturación y luminosidad. Ambas utilizan tres bytes por color; los colores de SNES utilizan dos.&lt;br /&gt;
&lt;br /&gt;
El resultado convertido de nuevo al formato de SNES se guarda en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;, que corresponde al buffer de paletas del juego.&lt;br /&gt;
&lt;br /&gt;
El sistema lleva indicadores para saber qué bases ya tiene preparadas. Si se pasa de un efecto RGB a uno HSL, no debe tomar los colores afectados como si fueran los originales.&lt;br /&gt;
&lt;br /&gt;
=== Preparar la base cuando hace falta ===&lt;br /&gt;
&lt;br /&gt;
Una paleta sin base registrada puede obtener sus colores del buffer del juego. Una carga explícita, como &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, proporciona los colores que deben utilizarse como base.&lt;br /&gt;
&lt;br /&gt;
La conversión a RGB o HSL se hace cuando se necesita. Después puede reutilizarse mientras no cambien los colores de origen.&lt;br /&gt;
&lt;br /&gt;
Cuando llegan colores nuevos, las conversiones y efectos anteriores dejan de servir. Las llamadas correspondientes de carga actualizan la base y borran los indicadores que deben volver a calcularse.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto ===&lt;br /&gt;
&lt;br /&gt;
El ID del efecto permite leer su tipo, valores y ratios en las tablas preparadas al instalar.&lt;br /&gt;
&lt;br /&gt;
Los canales utilizan valores de 0 a 31. Los ratios van de 0 a 127: 0 conserva el origen y 127 aplica por completo el cambio elegido.&lt;br /&gt;
&lt;br /&gt;
Un efecto puede modificar un canal, varios canales o mezclar los colores con los de otra paleta. Las transiciones utilizan los destinos RGB o HSL que ya se prepararon durante la instalación.&lt;br /&gt;
&lt;br /&gt;
Los cálculos se hacen fuera de NMI. La parte de NMI se encarga de copiar los colores resultantes, no de calcular cada efecto durante la transferencia.&lt;br /&gt;
&lt;br /&gt;
=== El efecto global ===&lt;br /&gt;
&lt;br /&gt;
El juego selecciona un ID global y elige mediante máscaras qué paletas deben recibirlo. El color fijo y el color 0,0 tienen sus propios indicadores.&lt;br /&gt;
&lt;br /&gt;
El administrador comprueba si cada paleta necesita una actualización. Si la base no cambió y sigue siendo válido el resultado del mismo efecto, puede reutilizarlo.&lt;br /&gt;
&lt;br /&gt;
Al cambiar el ID global, los resultados del efecto anterior dejan de servir, pero las bases RGB y HSL pueden seguir siendo válidas si sus colores de origen no cambiaron.&lt;br /&gt;
&lt;br /&gt;
Poner el ID global en 0 permite volver a los colores de base. Para restaurarlos, el sistema todavía tiene que procesar las paletas afectadas; no basta con dejar de trabajar sobre ellas.&lt;br /&gt;
&lt;br /&gt;
=== Combinar un efecto local con el global ===&lt;br /&gt;
&lt;br /&gt;
Un sprite puede necesitar un cambio de color propio y, además, recibir el efecto general del nivel. Por ejemplo, puede cambiar de tono y después oscurecerse junto con el resto de la pantalla.&lt;br /&gt;
&lt;br /&gt;
Las llamadas de concatenación permiten preparar el resultado local como base del efecto global. La variante RGB se utiliza con efectos RGB; la HSL, con efectos HSL.&lt;br /&gt;
&lt;br /&gt;
No hay que mostrar primero el resultado local sin el efecto global. Se prepara la base para que la carga final ya contenga la combinación correspondiente.&lt;br /&gt;
&lt;br /&gt;
Los recursos que comparten una paleta de CGRAM también comparten sus colores. Dos sprites que necesiten efectos locales diferentes deben disponer de destinos adecuados para mostrar ambos resultados.&lt;br /&gt;
&lt;br /&gt;
=== Cargar el resultado ===&lt;br /&gt;
&lt;br /&gt;
Cuando los colores están preparados, se solicita su transferencia a CGRAM. Esa carga también puede quedar pendiente si no se acepta por el presupuesto.&lt;br /&gt;
&lt;br /&gt;
Preparar una base o calcular un efecto no significa que ya esté en pantalla. El administrador confirma sus cambios de estado según el resultado de la carga y puede volver a intentar una actualización pendiente.&lt;br /&gt;
&lt;br /&gt;
Cuando corresponde, se mantiene un resultado anterior utilizable hasta poder sustituirlo. Esto permite distinguir una paleta que todavía está cambiando de una que nunca tuvo colores disponibles para mostrarse.&lt;br /&gt;
&lt;br /&gt;
Cargar directamente los colores originales antes del efecto podría hacer que se vieran un frame sin él. Por eso las cargas destinadas al efecto global preparan la base y dejan que se muestre el resultado ya procesado.&lt;br /&gt;
&lt;br /&gt;
== Cómo trabajan juntos ==&lt;br /&gt;
&lt;br /&gt;
Un sprite dinámico utiliza varias de estas partes durante el mismo frame. Su lógica elige una pose y una paleta; la asignación encuentra colores utilizables; la caché encuentra o prepara los gráficos; y el dibujo coloca sus piezas.&lt;br /&gt;
&lt;br /&gt;
Después, el administrador de efectos prepara los cambios globales que hagan falta y NMI realiza las transferencias solicitadas.&lt;br /&gt;
&lt;br /&gt;
Compartir gráficos, compartir una paleta y compartir una rutina de dibujo son tres cosas distintas. Dynamic Xtreme puede aprovechar cada una sin obligar a que los recursos compartan también las demás.&lt;br /&gt;
&lt;br /&gt;
== Lecturas relacionadas ==&lt;br /&gt;
&lt;br /&gt;
* [[es/Dynamic_Xtreme|Artículo principal]]: funcionalidades y compatibilidad.&lt;br /&gt;
* [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_sprite_creation_guide|Creación de sprites dinámicos]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_UberASM_guide|Dynamic Xtreme con UberASM]].&lt;br /&gt;
* [[es/Dynamic_Xtreme_ASM_API|API ASM]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21367</id>
		<title>es/Dynamic Xtreme internal workings</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_internal_workings&amp;diff=21367"/>
		<updated>2026-10-25T01:12:28Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: Created page with &amp;quot;{{Select Language|Dynamic_Xtreme_internal_workings}}  En este artículo se explica cómo funciona Dynamic Xtreme por dentro: cómo prepara las cargas de gráficos y paletas, cómo aprovecha NMI y cómo coordina el dibujo, las poses dinámicas y los efectos de color.  Los apartados comienzan con el recorrido general de un frame y los sistemas de carga. Después se explican las funcionalidades que aprovechan esos sistemas, hasta llegar a la caché de poses y los efectos de...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_internal_workings}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo funciona Dynamic Xtreme por dentro: cómo prepara las cargas de gráficos y paletas, cómo aprovecha NMI y cómo coordina el dibujo, las poses dinámicas y los efectos de color.&lt;br /&gt;
&lt;br /&gt;
Los apartados comienzan con el recorrido general de un frame y los sistemas de carga. Después se explican las funcionalidades que aprovechan esos sistemas, hasta llegar a la caché de poses y los efectos de paleta.&lt;br /&gt;
&lt;br /&gt;
== Organización general ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme tiene dos partes que trabajan en momentos distintos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;La herramienta de instalación&#039;&#039;&#039; lee los recursos, prepara sus datos, genera defines y rutinas, e instala el parche en la ROM.&lt;br /&gt;
* &#039;&#039;&#039;El parche&#039;&#039;&#039; ejecuta los sistemas durante el juego: administra el espacio disponible, prepara las transferencias y actualiza lo que se muestra en pantalla.&lt;br /&gt;
&lt;br /&gt;
La consola no lee los archivos DynamicInfo, DrawInfo o PaletteEffect originales. Al instalar, la herramienta los convierte en datos y código que el juego puede utilizar directamente.&lt;br /&gt;
&lt;br /&gt;
=== Qué prepara la instalación ===&lt;br /&gt;
&lt;br /&gt;
Los recursos gráficos y las paletas se guardan en la ROM. La herramienta genera tablas para localizar sus datos y consultar información como el tamaño de una pose o la rutina que debe dibujarla.&lt;br /&gt;
&lt;br /&gt;
Los DrawInfo también permiten generar rutinas de dibujo adaptadas a las características de cada grupo de poses. Así no es necesario interpretar el archivo de texto ni comprobar todas sus opciones durante cada frame.&lt;br /&gt;
&lt;br /&gt;
Los nombres publicados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; permiten que sprites, bloques y códigos UberASM encuentren esos recursos y las rutinas del sistema. Una reinstalación puede cambiar sus IDs o direcciones; por eso después hay que volver a insertar los recursos que dependen de ellos.&lt;br /&gt;
&lt;br /&gt;
=== Dónde se guarda cada cosa ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Memoria !! Qué contiene&lt;br /&gt;
|-&lt;br /&gt;
| ROM || Código del juego y recursos instalados: gráficos, paletas, tablas y rutinas de dibujo.&lt;br /&gt;
|-&lt;br /&gt;
| RAM || Estado del sistema durante el juego: poses cargadas, asignaciones de paletas, temporizadores, colores preparados y listas de transferencias.&lt;br /&gt;
|-&lt;br /&gt;
| VRAM || Gráficos y mapas de tiles que utiliza la consola para construir la imagen.&lt;br /&gt;
|-&lt;br /&gt;
| CGRAM || Colores de las paletas.&lt;br /&gt;
|-&lt;br /&gt;
| OAM || Datos de dibujo de los sprites: posición, tile, paleta, tamaño y propiedades de sus piezas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cargar una pose y dibujarla son trabajos distintos. Cargarla coloca sus gráficos en VRAM; dibujarla indica qué tiles utilizar y dónde mostrarlos. Del mismo modo, cargar una paleta cambia sus colores, pero no decide por sí solo qué sprite la utiliza.&lt;br /&gt;
&lt;br /&gt;
== Recorrido de un frame ==&lt;br /&gt;
&lt;br /&gt;
Durante el juego, los sprites y otros códigos deciden qué necesitan mostrar. Dynamic Xtreme prepara las cargas solicitadas y utiliza NMI para realizar las transferencias a la memoria de video.&lt;br /&gt;
&lt;br /&gt;
Este es el recorrido general en un modo de juego donde el sistema está habilitado:&lt;br /&gt;
&lt;br /&gt;
# NMI realiza las transferencias que se habían preparado y deja las listas disponibles para nuevas solicitudes.&lt;br /&gt;
# Se ejecuta la lógica del modo de juego: jugador, sprites, animaciones y otros códigos.&lt;br /&gt;
# Los recursos solicitan poses, paletas o transferencias y preparan sus datos de dibujo.&lt;br /&gt;
# La parte de paletas del game mode actualiza su estado y procesa los efectos globales que correspondan.&lt;br /&gt;
# En la siguiente oportunidad de NMI, se realizan las transferencias preparadas.&lt;br /&gt;
&lt;br /&gt;
No todo ocurre dentro de una única rutina. Dynamic Xtreme interviene en distintos puntos del juego para que el trabajo de preparación no tenga que hacerse durante las transferencias.&lt;br /&gt;
&lt;br /&gt;
== NMI y las transferencias de pantalla ==&lt;br /&gt;
&lt;br /&gt;
NMI es una interrupción que SNES puede generar al comenzar el intervalo de VBlank, cuando termina de dibujar la parte visible del frame. El juego aprovecha ese momento para actualizar gráficos, colores y otros datos de pantalla.&lt;br /&gt;
&lt;br /&gt;
Ese tiempo es limitado. La consola todavía tiene que realizar las tareas normales del juego, por lo que no se puede dedicar todo el intervalo a cargar poses dinámicas.&lt;br /&gt;
&lt;br /&gt;
=== Preparar una carga no es ejecutarla ===&lt;br /&gt;
&lt;br /&gt;
Cuando un código solicita una transferencia, normalmente no escribe los gráficos o colores en la memoria de video en ese mismo momento. Guarda una descripción de la carga en una lista de RAM.&lt;br /&gt;
&lt;br /&gt;
Cada entrada contiene los datos necesarios para realizarla:&lt;br /&gt;
&lt;br /&gt;
* Dirección y banco del origen.&lt;br /&gt;
* Cantidad de bytes.&lt;br /&gt;
* Destino en VRAM o CGRAM.&lt;br /&gt;
&lt;br /&gt;
Durante NMI, el parche lee esas entradas y utiliza DMA para copiar los datos. DMA es el mecanismo de la consola que realiza la transferencia sin necesitar un bucle de instrucciones para copiar cada byte.&lt;br /&gt;
&lt;br /&gt;
Una vez procesada la lista, sus entradas dejan de estar pendientes. Esto no borra los gráficos o colores que ya se copiaron: permanecen en su destino hasta que otro código los cambie.&lt;br /&gt;
&lt;br /&gt;
Si el origen está en RAM, sus datos deben seguir siendo válidos hasta que se ejecute la transferencia.&lt;br /&gt;
&lt;br /&gt;
=== Qué hace la rutina de Dynamic Xtreme ===&lt;br /&gt;
&lt;br /&gt;
En un game mode permitido, la rutina de NMI de Dynamic Xtreme reinicia el contador de datos del nuevo frame, actualiza sus relojes y realiza las transferencias de gráficos y paletas que estén pendientes.&lt;br /&gt;
&lt;br /&gt;
La lista de VRAM utiliza 0 para indicar que está vacía. La de CGRAM utiliza &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;; su contador representa el índice de la última entrada, no la cantidad de entradas.&lt;br /&gt;
&lt;br /&gt;
Las listas se recorren desde la última entrada hacia la primera. Si varios códigos escriben sobre el mismo destino, deben coordinarse: no conviene depender del orden de solicitudes para decidir qué recurso debe quedarse allí.&lt;br /&gt;
&lt;br /&gt;
El sistema no convierte todo el trabajo del juego en transferencias propias. Por ejemplo, el dibujo prepara datos OAM, y la actualización de OAM forma parte del flujo de pantalla del juego.&lt;br /&gt;
&lt;br /&gt;
=== Presupuesto de datos por frame ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; registra los bytes que las cargas del sistema han comprometido para el frame. &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; fija el límite que comprueban las solicitudes normales.&lt;br /&gt;
&lt;br /&gt;
El límite predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, es decir, 2048 bytes. Es una medida para controlar el trabajo de las transferencias; no significa que cualquier combinación de 2048 bytes tenga exactamente el mismo coste.&lt;br /&gt;
&lt;br /&gt;
Cuando una solicitud no cabe, puede rechazarse para intentarla después. Ese rechazo no queda automáticamente guardado en una lista de espera para otro frame: el código que la necesita debe volver a solicitarla.&lt;br /&gt;
&lt;br /&gt;
Las transferencias &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; omiten la comprobación del límite, pero también suman sus bytes al contador. No hacen que la consola tenga más tiempo; permiten dar prioridad a cargas que no deben quedar sujetas a esa comprobación.&lt;br /&gt;
&lt;br /&gt;
== Game modes e inicialización ==&lt;br /&gt;
&lt;br /&gt;
SMW utiliza game modes para separar estados como la carga del nivel, el juego dentro de un nivel y las pantallas de transición. El modo actual se guarda en &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme consulta una tabla para decidir en cuáles debe funcionar. No todos los modos necesitan mantener una caché de poses o preparar cargas dinámicas.&lt;br /&gt;
&lt;br /&gt;
=== Modos permitidos y reinicio del sistema ===&lt;br /&gt;
&lt;br /&gt;
En los modos no permitidos, la parte de game mode reinicializa el estado de Dynamic Xtreme. Así no se arrastran asignaciones o referencias que pertenecían a otra pantalla.&lt;br /&gt;
&lt;br /&gt;
La inicialización prepara las listas de transferencias, los contadores y el estado de los sistemas habilitados. También establece valores iniciales como el presupuesto de datos por frame y las marcas que indican que todavía no hay una asignación válida.&lt;br /&gt;
&lt;br /&gt;
Mientras el juego permanezca en un modo no permitido, ese reinicio puede repetirse. No depende únicamente de detectar que cambió el número de game mode.&lt;br /&gt;
&lt;br /&gt;
Algunas llamadas tienen comprobaciones más restrictivas que la tabla general. Que Dynamic Xtreme esté activo en una pantalla no significa que todas las rutinas de sprites deban solicitar nuevas poses allí.&lt;br /&gt;
&lt;br /&gt;
=== Trabajo durante el game mode ===&lt;br /&gt;
&lt;br /&gt;
La parte de game mode integra las tareas que no necesitan ejecutarse dentro de NMI. Según las funcionalidades habilitadas, incluye el procesamiento del control, la preparación de actualizaciones de VRAM y el mantenimiento y procesamiento de paletas.&lt;br /&gt;
&lt;br /&gt;
Después de la ejecución del modo de juego, el sistema de paletas limpia las marcas de actualización del frame y reduce los temporizadores que protegen sus asignaciones, cuando corresponde. El procesamiento de efectos globales también se realiza en esta parte, no durante la copia de cada color en NMI.&lt;br /&gt;
&lt;br /&gt;
=== Dos relojes distintos ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; avanza cuando se ejecuta la rutina correspondiente de NMI, incluso durante la pausa. Se utiliza, entre otras cosas, para saber cuánto tiempo lleva una pose sin utilizarse.&lt;br /&gt;
* &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; no avanza cuando el juego está pausado o la acción está congelada. Sirve para coordinar animaciones que deban detenerse junto con el juego.&lt;br /&gt;
&lt;br /&gt;
Por eso una pose puede acumular tiempo sin uso durante la pausa, aunque una animación basada en &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; permanezca detenida.&lt;br /&gt;
&lt;br /&gt;
== Carga de gráficos: GraphicsChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt; proporciona la base para programar transferencias a VRAM. La utilizan tanto las animaciones de tiles como los sistemas del jugador, Yoshi y poses dinámicas.&lt;br /&gt;
&lt;br /&gt;
Una transferencia indica de dónde vienen los gráficos, cuánto ocupan y dónde deben colocarse. La macro comprueba el presupuesto, añade la entrada a la lista y actualiza el contador de datos si se acepta la carga.&lt;br /&gt;
&lt;br /&gt;
Este sistema de carga no decide qué imagen debe seguir en una animación ni qué región de VRAM pertenece a cada recurso. Esas decisiones corresponden al código que solicita la transferencia o, en el caso de las poses dinámicas, a su administrador de espacio.&lt;br /&gt;
&lt;br /&gt;
=== Animaciones sobre un destino fijo ===&lt;br /&gt;
&lt;br /&gt;
Una animación de tiles puede copiar distintas imágenes al mismo destino. Los tiles del nivel siguen utilizando los mismos números, pero los gráficos que hay en esas posiciones van cambiando.&lt;br /&gt;
&lt;br /&gt;
El código de animación elige el origen de cada paso y solicita la carga. Si la transferencia se rechaza, puede conservar el paso anterior y volver a intentarlo sin avanzar su estado.&lt;br /&gt;
&lt;br /&gt;
Esto permite que las animaciones compartan el presupuesto con otros recursos dinámicos en lugar de realizar cargas sin tener en cuenta el trabajo ya solicitado.&lt;br /&gt;
&lt;br /&gt;
=== Gráficos de poses dinámicas ===&lt;br /&gt;
&lt;br /&gt;
Una pose no siempre se puede copiar como un bloque único de bytes a VRAM. El formato de tiles del sprite puede requerir repartir sus datos entre distintas filas.&lt;br /&gt;
&lt;br /&gt;
La instalación prepara la información necesaria para esas cargas. Durante el juego, &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; calcula los destinos a partir del lugar asignado a la pose y genera las entradas de transferencia correspondientes.&lt;br /&gt;
&lt;br /&gt;
La decisión de cargar una pose y encontrarle espacio ocurre antes de ese paso. &amp;lt;code&amp;gt;DynamicRoutine&amp;lt;/code&amp;gt; prepara la copia de sus gráficos; no realiza por sí sola toda la administración de la caché.&lt;br /&gt;
&lt;br /&gt;
== Carga y asignación de paletas: PalettesChange ==&lt;br /&gt;
&lt;br /&gt;
Una paleta instalada y una paleta de pantalla no son lo mismo. La primera es un conjunto de colores guardados en ROM; la segunda es un lugar de CGRAM donde esos colores pueden utilizarse para dibujar.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, un sprite puede solicitar los colores de su paleta azul sin exigir que se coloquen siempre en la paleta 9. La asignación automática elige un destino disponible entre las paletas de sprites permitidas.&lt;br /&gt;
&lt;br /&gt;
=== Carga directa de colores ===&lt;br /&gt;
&lt;br /&gt;
Las transferencias a CGRAM se preparan en una lista, de forma similar a las cargas de gráficos. El destino se expresa como número de color y el tamaño como cantidad de bytes; cada color de SNES ocupa dos bytes.&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; también mantienen las copias de colores que necesitan SMW y Dynamic Xtreme. No basta con cambiar CGRAM: otras rutinas, como la animación de victoria del goal, pueden volver a utilizar los colores guardados por el juego.&lt;br /&gt;
&lt;br /&gt;
Si la paleta va a recibir un efecto global, la macro prepara sus colores originales para que se aplique el efecto antes de mostrarlos. La carga del resultado se realiza después mediante el sistema de efectos.&lt;br /&gt;
&lt;br /&gt;
=== Asignación automática ===&lt;br /&gt;
&lt;br /&gt;
El administrador guarda qué ID de paleta ocupa cada destino y cuánto tiempo debe permanecer protegido. Para asignar una paleta, busca primero si ya existe una asignación con los mismos colores identificados por su ID y una condición de efecto compatible.&lt;br /&gt;
&lt;br /&gt;
Si existe, puede compartir ese destino. Si no existe, busca un lugar libre y, después, uno que pueda reemplazarse porque dejó de estar protegido.&lt;br /&gt;
&lt;br /&gt;
Esto evita cargar varias copias de una misma paleta para distintos sprites que pueden compartirla.&lt;br /&gt;
&lt;br /&gt;
En las tablas de asignación, &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; identifica una entrada libre y &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; una entrada reservada que la asignación automática no debe reemplazar.&lt;br /&gt;
&lt;br /&gt;
=== Protección mientras se utiliza ===&lt;br /&gt;
&lt;br /&gt;
Cuando un recurso utiliza una paleta, su temporizador de protección se mantiene en 2. Mientras continúe solicitándola, otros recursos no deben reemplazarla automáticamente.&lt;br /&gt;
&lt;br /&gt;
Que el temporizador llegue a cero no borra los colores ni elimina inmediatamente su ID. La asignación puede seguir reutilizándose si se solicita la misma paleta antes de que otro recurso la reemplace.&lt;br /&gt;
&lt;br /&gt;
Los destinos manuales permiten elegir dónde colocar la paleta, y el modo manual sin carga permite utilizar colores que ya estaban preparados. Elegir el mismo destino para dos recursos con colores distintos sigue siendo responsabilidad de esos recursos.&lt;br /&gt;
&lt;br /&gt;
=== Versión y cambios de paleta ===&lt;br /&gt;
&lt;br /&gt;
En las rutinas de sprites, la versión selecciona una entrada de la lista de paletas del DynamicInfo. El sistema guarda también la última versión procesada para detectar si debe cambiar la selección.&lt;br /&gt;
&lt;br /&gt;
No es necesario volver a cargar los colores cada frame si la selección sigue siendo válida. Mantener la protección de una paleta no significa que sus colores se hayan transferido otra vez.&lt;br /&gt;
&lt;br /&gt;
== Dibujo de poses: DrawingSystem ==&lt;br /&gt;
&lt;br /&gt;
El sistema de dibujo recibe una pose y la información necesaria para situarla en pantalla. A partir de los datos generados desde el DrawInfo, prepara las entradas OAM de sus tiles.&lt;br /&gt;
&lt;br /&gt;
=== Rutinas generadas durante la instalación ===&lt;br /&gt;
&lt;br /&gt;
La herramienta analiza qué tablas utiliza cada pose: tiles, posiciones, tamaños, propiedades y desplazamientos para los volteos.&lt;br /&gt;
&lt;br /&gt;
Las poses con características compatibles pueden compartir una misma rutina de dibujo, aunque mantengan sus propios IDs y datos. La rutina generada incluye el tratamiento que necesita ese grupo, en lugar de interpretar todas las posibilidades del formato durante cada llamada.&lt;br /&gt;
&lt;br /&gt;
=== Preparación de los tiles ===&lt;br /&gt;
&lt;br /&gt;
El dibujo combina la posición del recurso con los desplazamientos de cada tile, aplica los volteos y prepara el número de tile y sus propiedades.&lt;br /&gt;
&lt;br /&gt;
En una pose dinámica, los números de tile se ajustan al lugar donde quedaron cargados sus gráficos. En una pose estática se utilizan sus posiciones fijas. Si la pose toma un tile común desde &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, el código que la dibuja debe preparar ese valor.&lt;br /&gt;
&lt;br /&gt;
También se comprueba si los tiles pueden verse en pantalla y si quedan entradas OAM disponibles. Los tiles descartados no generan un dibujo visible, aunque la pose tenga sus gráficos en VRAM.&lt;br /&gt;
&lt;br /&gt;
=== Prioridad y espacio de OAM ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme organiza el espacio OAM teniendo en cuenta la prioridad de dibujo. En LoROM utiliza su propio seguimiento de entradas disponibles; en SA-1 aprovecha la integración con MaxTile.&lt;br /&gt;
&lt;br /&gt;
La prioridad de dibujo ayuda a decidir el orden de las piezas de sprites. No debe confundirse con la propiedad que determina cómo se combinan con las capas del fondo.&lt;br /&gt;
&lt;br /&gt;
El sistema no elimina los límites de sprites y tiles que SNES puede mostrar en una misma línea de pantalla.&lt;br /&gt;
&lt;br /&gt;
== Jugador y Yoshi ==&lt;br /&gt;
&lt;br /&gt;
=== PlayerFeatures ===&lt;br /&gt;
&lt;br /&gt;
SMW utiliza rutinas específicas para elegir y cargar las piezas gráficas del jugador. &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; integra esas cargas con Dynamic Xtreme y permite cambiar su origen de gráficos y paletas.&lt;br /&gt;
&lt;br /&gt;
Para gráficos con la organización original, la rutina calcula las direcciones de las piezas que necesita la pose actual. Compara sus orígenes con los anteriores y prepara las cargas de las piezas que hayan cambiado.&lt;br /&gt;
&lt;br /&gt;
Estas cargas utilizan transferencias forzadas. Así mantienen su prioridad, y los bytes que ocupan también cuentan para las solicitudes normales que se realizan después.&lt;br /&gt;
&lt;br /&gt;
La paleta del jugador tiene un tratamiento especial y no se sustituye únicamente cambiando una paleta de sprite cualquiera. Su código combina la selección de colores del juego con el origen personalizado que se haya configurado.&lt;br /&gt;
&lt;br /&gt;
El soporte para sistemas de jugador personalizados permite utilizar otras formas de administrar sus poses y dibujo; no convierte automáticamente un spritesheet arbitrario al formato del jugador original.&lt;br /&gt;
&lt;br /&gt;
=== YoshiFeatures ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; permite cambiar el origen de los gráficos que utilizan las rutinas de Yoshi manteniendo la organización esperada de sus piezas.&lt;br /&gt;
&lt;br /&gt;
Su código calcula las direcciones que necesita cada pieza y prepara sus transferencias a las posiciones correspondientes de VRAM. Como las cargas del jugador, estas actualizaciones tienen un tratamiento prioritario.&lt;br /&gt;
&lt;br /&gt;
Esta funcionalidad depende de &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;. Ambas intervienen en el manejo de gráficos del juego, por lo que las restricciones de compatibilidad del sistema del jugador también afectan al uso de Yoshi.&lt;br /&gt;
&lt;br /&gt;
== Memoria y optimizaciones ==&lt;br /&gt;
&lt;br /&gt;
=== Free7E2000 ===&lt;br /&gt;
&lt;br /&gt;
SMW conserva en RAM gráficos originales que utiliza para el jugador, Yoshi y determinadas animaciones. En ROMs sin SA-1, &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; adapta esas cargas para leer los datos correspondientes desde ROM.&lt;br /&gt;
&lt;br /&gt;
El área recuperada se utiliza para las variables internas de Dynamic Xtreme. No se convierte en una zona libre que cualquier otro recurso pueda ocupar.&lt;br /&gt;
&lt;br /&gt;
En SA-1, el sistema utiliza otras direcciones y esta opción se desactiva. Los rangos y la forma de reubicarlos están documentados en [[es/Dynamic_Xtreme#Espacios_de_RAM_utilizados|Compatibilidad: espacios de RAM utilizados]].&lt;br /&gt;
&lt;br /&gt;
=== ControllerOptimization ===&lt;br /&gt;
&lt;br /&gt;
El procesamiento del control que normalmente se ejecutaría desde NMI se realiza en la parte de game mode.&lt;br /&gt;
&lt;br /&gt;
El propósito es dejar más tiempo disponible dentro de NMI, no añadir un frame de retraso al control ni cambiar los botones que recibe el juego.&lt;br /&gt;
&lt;br /&gt;
=== FixedColorOptimization ===&lt;br /&gt;
&lt;br /&gt;
El color fijo es un color que la consola puede utilizar para sus mezclas de color. Su actualización necesita preparar los componentes que se escriben en el registro correspondiente.&lt;br /&gt;
&lt;br /&gt;
Esta optimización sustituye la rutina original por una secuencia más corta para realizar ese trabajo. El color sigue teniendo que enviarse a la consola; se reduce la preparación necesaria durante NMI.&lt;br /&gt;
&lt;br /&gt;
=== KevinLMVRAMOptimization ===&lt;br /&gt;
&lt;br /&gt;
Lunar Magic utiliza listas de actualizaciones llamadas stripe images para modificar partes de los mapas de tiles. Esas listas contienen tanto los datos como información sobre sus destinos.&lt;br /&gt;
&lt;br /&gt;
La integración de la optimización de Kevin realiza fuera de NMI parte del procesamiento que adapta los destinos de esas actualizaciones. La transferencia de los datos de pantalla sigue necesitando ejecutarse en el momento correspondiente.&lt;br /&gt;
&lt;br /&gt;
La opción integrada sustituye el uso del parche original por separado. Su restricción de desinstalación debe tenerse en cuenta antes de activarla.&lt;br /&gt;
&lt;br /&gt;
=== StatusBarOptimization ===&lt;br /&gt;
&lt;br /&gt;
La barra de estado original actualiza regiones concretas de VRAM. Esta optimización prepara de forma más directa las transferencias que necesita, reduciendo el trabajo de configuración de DMA durante NMI.&lt;br /&gt;
&lt;br /&gt;
No reemplaza la barra por una nueva. Como modifica la rutina de actualización de la original, puede entrar en conflicto con recursos que la sustituyen, modifican o eliminan.&lt;br /&gt;
&lt;br /&gt;
== Sistema de sprites dinámicos: DynamicPoses ==&lt;br /&gt;
&lt;br /&gt;
El sistema de poses dinámicas trata el espacio disponible de VRAM como una caché compartida. Conserva poses que ya se cargaron para reutilizarlas y reemplaza las que han dejado de utilizarse cuando necesita espacio.&lt;br /&gt;
&lt;br /&gt;
Un sprite no recibe necesariamente una región fija para todas sus poses. Solicita la pose que necesita y obtiene la referencia al lugar donde puede dibujarla.&lt;br /&gt;
&lt;br /&gt;
=== Compartir una pose ===&lt;br /&gt;
&lt;br /&gt;
Supongamos que varios sprites solicitan la misma pose. La primera solicitud puede necesitar cargar sus gráficos; las siguientes encuentran la misma pose registrada y utilizan su ubicación.&lt;br /&gt;
&lt;br /&gt;
No hace falta cargar una copia por cada entidad. Cada una puede dibujarla en una posición distinta usando los mismos gráficos.&lt;br /&gt;
&lt;br /&gt;
Esta reutilización se realiza por el ID de la pose. Que dos recursos distintos tengan gráficos visualmente iguales no significa, por sí solo, que sean la misma entrada de la caché.&lt;br /&gt;
&lt;br /&gt;
=== Buscar una pose ya registrada ===&lt;br /&gt;
&lt;br /&gt;
El sistema mantiene una tabla de búsqueda con el ID de cada pose registrada, su ubicación en VRAM y el momento en que se utilizó por última vez.&lt;br /&gt;
&lt;br /&gt;
Para no recorrer siempre todas las poses, calcula un índice de búsqueda a partir del ID. La implementación utiliza una tabla hash de 128 entradas: el índice permite comenzar la búsqueda y el ID completo confirma si se encontró la pose correcta.&lt;br /&gt;
&lt;br /&gt;
Si la pose ya está registrada, se actualiza su tiempo de último uso y se devuelve su referencia. No se prepara otra carga de gráficos.&lt;br /&gt;
&lt;br /&gt;
=== Solicitar una pose nueva ===&lt;br /&gt;
&lt;br /&gt;
Cuando la pose no está registrada, el recorrido general es:&lt;br /&gt;
&lt;br /&gt;
# Consultar cuánto ocupan sus gráficos y cuántos bloques de VRAM necesita.&lt;br /&gt;
# Comprobar si sus bytes caben en el presupuesto del frame.&lt;br /&gt;
# Buscar un espacio adecuado que no esté reservado ni protegido.&lt;br /&gt;
# Retirar las referencias de las poses que deban reemplazarse en ese espacio.&lt;br /&gt;
# Registrar la nueva pose y su ubicación.&lt;br /&gt;
# Preparar las transferencias necesarias para colocar sus gráficos allí.&lt;br /&gt;
&lt;br /&gt;
Si no hay presupuesto o espacio adecuado, la solicitud falla. No se completa parcialmente la asignación para obligar después al sprite a dibujar una pose que todavía no tiene preparada.&lt;br /&gt;
&lt;br /&gt;
=== Mapa de espacio disponible ===&lt;br /&gt;
&lt;br /&gt;
El mapa de VRAM distingue regiones reservadas, espacios libres y espacios ocupados por poses. Su unidad de reserva corresponde a bloques de gráficos de 16×16.&lt;br /&gt;
&lt;br /&gt;
Las configuraciones de espacio indican qué partes de SP1-SP4 pueden utilizarse. El administrador no puede elegir una zona reservada para los gráficos fijos del nivel, el jugador u otro sistema.&lt;br /&gt;
&lt;br /&gt;
Cada región conserva la información necesaria para conocer su comienzo y tamaño. Esto permite recorrer regiones completas en lugar de tratar cada tile como una asignación independiente.&lt;br /&gt;
&lt;br /&gt;
Un espacio libre más grande puede dividirse al colocar una pose. También pueden considerarse regiones contiguas para obtener el espacio que necesita una solicitud.&lt;br /&gt;
&lt;br /&gt;
=== Protección y elección de reemplazo ===&lt;br /&gt;
&lt;br /&gt;
El tiempo desde el último uso indica cuándo puede reemplazarse una pose. Las utilizadas demasiado recientemente quedan protegidas: el administrador exige una antigüedad de al menos dos frames para considerar su espacio.&lt;br /&gt;
&lt;br /&gt;
Entre las regiones utilizables, se favorecen las poses con mayor tiempo sin uso. Cuando la antigüedad es equivalente, se prefiere el espacio adecuado más pequeño para no consumir innecesariamente una región mayor.&lt;br /&gt;
&lt;br /&gt;
Si una región contiene varias poses, no basta con que una de ellas sea antigua: la protección de las demás también cuenta al decidir si puede utilizarse todo ese espacio.&lt;br /&gt;
&lt;br /&gt;
La protección no obliga a borrar una pose cuando deja de utilizarse. Puede permanecer registrada y reutilizarse más adelante sin una carga nueva, siempre que no haya sido reemplazada.&lt;br /&gt;
&lt;br /&gt;
=== Qué ocurre si no se puede cambiar de pose ===&lt;br /&gt;
&lt;br /&gt;
Las rutinas de carga para sprites pueden conservar la referencia a una pose anterior válida. Si una nueva solicitud falla, mantienen protegida esa pose anterior para que el sprite pueda continuar dibujándola.&lt;br /&gt;
&lt;br /&gt;
Por eso hay que distinguir entre conseguir exactamente la pose nueva y disponer de una pose utilizable. El carry de una llamada con soporte para conservar la anterior puede indicar éxito aunque todavía no se haya cambiado a la pose solicitada.&lt;br /&gt;
&lt;br /&gt;
Si nunca hubo una pose válida, no existe una anterior que se pueda mostrar. El código debe respetar ese resultado antes de dibujar.&lt;br /&gt;
&lt;br /&gt;
=== Carga, dibujo y lógica del sprite ===&lt;br /&gt;
&lt;br /&gt;
El administrador de poses no decide cómo se mueve o anima el personaje. El sprite elige su pose, solicita sus gráficos y utiliza el sistema de dibujo con el resultado disponible.&lt;br /&gt;
&lt;br /&gt;
La comprobación de visibilidad permite evitar parte del trabajo gráfico cuando el sprite no necesita dibujarse. La short routine mantiene la lógica que corresponda; la long routine incluye el trabajo de paleta, pose y dibujo.&lt;br /&gt;
&lt;br /&gt;
Mantener esas tareas separadas permite utilizar la misma infraestructura para sprites normales, cluster, extended y otros códigos.&lt;br /&gt;
&lt;br /&gt;
== Efectos de paleta: PalettesEffects ==&lt;br /&gt;
&lt;br /&gt;
El sistema de efectos transforma colores sin perder la referencia a los colores originales. Esto permite cambiar de efecto, combinar un efecto local con uno global o volver a la paleta sin efecto.&lt;br /&gt;
&lt;br /&gt;
Los cálculos se realizan fuera de NMI. NMI recibe las transferencias con el resultado que debe mostrarse.&lt;br /&gt;
&lt;br /&gt;
=== Colores originales y colores resultantes ===&lt;br /&gt;
&lt;br /&gt;
El sistema distingue varias representaciones de una paleta:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Datos !! Para qué se utilizan&lt;br /&gt;
|-&lt;br /&gt;
| Colores originales en formato SNES || Guardan la base que debe conservarse antes de aplicar el efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| Base RGB || Separa rojo, verde y azul para los efectos que trabajan con esos componentes.&lt;br /&gt;
|-&lt;br /&gt;
| Base HSL || Separa tono, saturación y luminosidad para los efectos de ese tipo.&lt;br /&gt;
|-&lt;br /&gt;
| Colores resultantes en formato SNES || Contienen el resultado que puede copiarse a CGRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; conserva la base en formato SNES. Las bases RGB y HSL utilizan tres bytes por color. El resultado preparado para pantalla utiliza dos bytes por color y se guarda en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;, que corresponde al buffer de paletas del juego.&lt;br /&gt;
&lt;br /&gt;
Los indicadores de base cargada permiten saber qué representaciones ya están preparadas. Cambiar de un efecto RGB a uno HSL no debe convertir el resultado afectado en los nuevos colores originales.&lt;br /&gt;
&lt;br /&gt;
=== Preparar y reutilizar una base ===&lt;br /&gt;
&lt;br /&gt;
Si una paleta no tiene todavía una base registrada, el sistema puede obtener sus colores del buffer del juego. Las cargas explícitas, como &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, proporcionan directamente los colores que deben servir de base.&lt;br /&gt;
&lt;br /&gt;
La conversión a RGB o HSL se realiza cuando hace falta esa representación. Una vez preparada, puede reutilizarse mientras no cambien sus colores de origen.&lt;br /&gt;
&lt;br /&gt;
Cuando se cargan colores nuevos, deben invalidarse las conversiones y los resultados anteriores que dependían de ellos. Las llamadas de carga correspondientes se encargan de ese mantenimiento.&lt;br /&gt;
&lt;br /&gt;
=== Qué describe un efecto ===&lt;br /&gt;
&lt;br /&gt;
Cada efecto instalado tiene un ID y datos que indican su tipo, los valores de sus canales y sus ratios.&lt;br /&gt;
&lt;br /&gt;
Los canales RGB y HSL utilizan valores de 0 a 31. Los ratios utilizan 0 a 127: 0 conserva el origen y 127 aplica por completo el cambio indicado.&lt;br /&gt;
&lt;br /&gt;
Los efectos de mezcla modifican uno o varios componentes. Los de transición utilizan otra paleta como destino. Durante la instalación, las paletas de destino se convierten al formato RGB o HSL que utilizará el efecto, evitando hacer esa conversión del destino en cada llamada.&lt;br /&gt;
&lt;br /&gt;
=== Efecto global ===&lt;br /&gt;
&lt;br /&gt;
El efecto global se selecciona con un ID compartido. Las máscaras de paletas indican cuáles deben recibirlo; el color fijo y el color 0,0 tienen sus propios indicadores de participación.&lt;br /&gt;
&lt;br /&gt;
El administrador revisa si cada paleta necesita procesarse. Si conserva la misma base y el resultado del mismo efecto sigue siendo válido, no es necesario calcularlo otra vez.&lt;br /&gt;
&lt;br /&gt;
Cuando cambia el ID global, se marcan como pendientes los resultados que dependían del efecto anterior. Las bases de color pueden seguir utilizándose si sus colores originales no cambiaron.&lt;br /&gt;
&lt;br /&gt;
El ID global 0 permite volver a los colores de base. No equivale simplemente a dejar de procesar las paletas: el sistema debe preparar la restauración de las que estaban afectadas.&lt;br /&gt;
&lt;br /&gt;
=== Efectos locales y concatenación ===&lt;br /&gt;
&lt;br /&gt;
Un efecto local permite modificar la paleta de un recurso concreto. Si además debe recibir el efecto global, los dos cambios tienen que aplicarse en el orden previsto.&lt;br /&gt;
&lt;br /&gt;
Las llamadas de concatenación permiten utilizar el resultado local como base del efecto global. Por ejemplo, un sprite puede recibir un cambio de tono propio y después el efecto de oscurecimiento del nivel.&lt;br /&gt;
&lt;br /&gt;
La concatenación RGB se utiliza con efectos RGB; la HSL, con efectos HSL. Preparar una base local no implica que haya que cargar primero sus colores sin el efecto global.&lt;br /&gt;
&lt;br /&gt;
Una paleta de CGRAM sigue siendo compartida por todos los recursos que la utilizan. Si dos sprites necesitan resultados locales distintos, no deben depender del mismo destino de paleta para mostrarlos simultáneamente.&lt;br /&gt;
&lt;br /&gt;
=== Publicar el resultado ===&lt;br /&gt;
&lt;br /&gt;
Después del cálculo, los colores se convierten al formato de SNES y se programa su transferencia. Esa solicitud también debe respetar el presupuesto correspondiente.&lt;br /&gt;
&lt;br /&gt;
Preparar los colores originales o calcular un efecto no significa que el resultado ya se haya enviado a CGRAM. El administrador confirma el avance de sus estados según el resultado de la carga, y puede volver a intentar una actualización pendiente.&lt;br /&gt;
&lt;br /&gt;
Cuando corresponde, las rutinas conservan el resultado anterior utilizable mientras el nuevo todavía no está disponible. Esto evita confundir una actualización pendiente con la ausencia total de una paleta que se pueda mostrar.&lt;br /&gt;
&lt;br /&gt;
Enviar primero los colores originales directamente a CGRAM rompería esa separación: la paleta podría verse un frame sin efecto antes de mostrar el resultado correcto. Por eso las cargas destinadas al efecto global preparan la base sin publicar antes una versión sin efecto.&lt;br /&gt;
&lt;br /&gt;
== Integración de los sistemas ==&lt;br /&gt;
&lt;br /&gt;
El funcionamiento de un sprite dinámico reúne varios sistemas sin convertirlos en una sola tarea:&lt;br /&gt;
&lt;br /&gt;
# Su lógica elige la pose y la variante de paleta que necesita.&lt;br /&gt;
# La asignación de paletas busca un destino utilizable y prepara los colores cuando hace falta.&lt;br /&gt;
# La caché busca la pose o encuentra espacio para cargarla.&lt;br /&gt;
# El dibujo utiliza la referencia disponible para preparar sus tiles en OAM.&lt;br /&gt;
# El administrador de efectos prepara los cambios globales pendientes sobre las paletas habilitadas.&lt;br /&gt;
# NMI realiza las transferencias de gráficos y colores que quedaron programadas.&lt;br /&gt;
&lt;br /&gt;
Compartir gráficos, compartir colores y compartir una rutina de dibujo son optimizaciones distintas. Un recurso puede aprovechar una de ellas sin que eso implique que deba compartir todas las demás.&lt;br /&gt;
&lt;br /&gt;
== Lecturas relacionadas ==&lt;br /&gt;
&lt;br /&gt;
* [[es/Dynamic_Xtreme|Artículo principal]]: funcionalidades y compatibilidad.&lt;br /&gt;
* [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]]: datos que utiliza la instalación.&lt;br /&gt;
* [[es/Dynamic_Xtreme_sprite_creation_guide|Creación de sprites dinámicos]]: aplicación práctica en un sprite.&lt;br /&gt;
* [[es/Dynamic_Xtreme_UberASM_guide|Dynamic Xtreme con UberASM]]: configuración y ejemplos de nivel.&lt;br /&gt;
* [[es/Dynamic_Xtreme_ASM_API|API ASM]]: parámetros y resultados de las llamadas.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21366</id>
		<title>es/Dynamic Xtreme</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21366"/>
		<updated>2026-10-25T00:59:13Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es una herramienta de soporte dinámico avanzada para Super Mario World en el SNES. Desarrollada para la comunidad de ROM hacking, permite realizar cambios gráficos y de paletas en tiempo real durante la ejecución del juego, ampliando considerablemente las capacidades técnicas originales del hardware del SNES.La herramienta se centra en ofrecer un sistema completo y flexible de gráficos dinámicos, con énfasis en el rendimiento y la modularidad. &lt;br /&gt;
&lt;br /&gt;
Entre sus características principales se incluyen:&lt;br /&gt;
* Cambios gráficos y de paleta en tiempo real (on-the-fly).&lt;br /&gt;
* El sistema de Dynamic Sprite más potente y flexible disponible para Super Mario World.&lt;br /&gt;
* Advanced Drawing System, que permite dibujar cualquier frame registrado en pantalla con control total sobre prioridad, capa, desplazamiento (offset) y propiedades.&lt;br /&gt;
* Efectos de paleta avanzados, que incluyen modificación en tiempo real mediante tono (hue), saturación, brillo, fusión de colores, transiciones suaves y control individual de canales RGB y HSL.&lt;br /&gt;
* Reemplazo completo de gráficos y paletas del jugador, compatible con cualquier tamaño de Mario, cualquier cantidad de frames y cualquier estilo de animación.&lt;br /&gt;
* Soporte total para el reemplazo de gráficos de Yoshi.&lt;br /&gt;
* Optimizaciones intensivas en el NMI-handler para maximizar el rendimiento.&lt;br /&gt;
&lt;br /&gt;
Las funciones de Dynamic Xtreme se seleccionan durante la instalación para utilizar solo las que necesita el proyecto. Algunas tienen dependencias, problemas de compatibilidad o restricciones para desinstalarlas; revisa las advertencias de cada opción. La herramienta fue creada con el objetivo de facilitar la implementación de efectos visuales complejos en hacks de Super Mario World manteniendo un alto nivel de compatibilidad y estabilidad.&lt;br /&gt;
&lt;br /&gt;
== Objetivos del proyecto ==&lt;br /&gt;
&lt;br /&gt;
El principal objetivo de Dynamic Xtreme es facilitar el uso de sprites dinámicos y ofrecer un soporte completo para cambios de gráficos, paletas y tilemaps en tiempo real.&lt;br /&gt;
&lt;br /&gt;
El proyecto busca aprovechar al máximo el potencial del SNES sin requerir que el usuario tenga conocimientos avanzados sobre el hardware interno de la consola. Muchos sistemas dinámicos tradicionales suelen ser complejos y dependen fuertemente de conceptos técnicos como VRAM, CGRAM, OAM o DMA. Dynamic Xtreme intenta abstraer gran parte de esa complejidad mediante herramientas y formatos más modernos, legibles y fáciles de utilizar.&lt;br /&gt;
&lt;br /&gt;
Otro de los objetivos principales del proyecto es mantener un alto rendimiento incluso en situaciones visualmente complejas, permitiendo el uso intensivo de gráficos dinámicos, efectos de paletas y sistemas avanzados de renderizado sin comprometer innecesariamente la performance.&lt;br /&gt;
&lt;br /&gt;
Además, Dynamic Xtreme busca que los sprites dinámicos puedan utilizarse de una forma tan natural y sencilla como si fueran sprites normales. La idea es que las personas enfocadas en level design o creación de contenido no necesiten preocuparse constantemente por las limitaciones técnicas internas del sistema y puedan trabajar con recursos dinámicos de forma transparente y práctica.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades ==&lt;br /&gt;
&lt;br /&gt;
Durante la instalación puedes elegir qué funcionalidades habilitar. Los nombres entre paréntesis corresponden a las opciones del instalador y de &amp;lt;code&amp;gt;Settings.json&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Gráficos, poses y paletas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de gráficos (&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;) || Permite cargar gráficos durante el juego. Es la base para las animaciones de tiles, los cambios de gráficos del nivel y las poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de paletas (&amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;) || Permite cargar y administrar paletas durante el juego. Incluye la asignación automática de paletas para que los sprites puedan compartir los mismos colores sin cargarlos varias veces.&lt;br /&gt;
|-&lt;br /&gt;
| Poses dinámicas (&amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;) || Administra el espacio de VRAM como una caché de poses: reutiliza las que ya están cargadas, permite compartirlas entre entidades y elige cuáles reemplazar cuando hace falta espacio. Así evita cargas innecesarias.&lt;br /&gt;
|-&lt;br /&gt;
| Dibujo de poses (&amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;) || Dibuja las poses definidas en archivos DrawInfo, tanto dinámicas como estáticas. Permite controlar sus tiles, posición, volteo, paleta y prioridad de dibujo.&lt;br /&gt;
|-&lt;br /&gt;
| Efectos de paleta (&amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;) || Permite cambiar colores mediante efectos RGB y HSL: teñir paletas, modificar tono, saturación o luminosidad, y realizar transiciones entre paletas. Pueden aplicarse a recursos individuales o como un efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La carga de poses dinámicas y el dibujo son sistemas separados: puedes dibujar una pose estática sin cargar sus gráficos dinámicamente.&lt;br /&gt;
&lt;br /&gt;
=== Jugador y Yoshi ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Funciones del jugador (&amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos y paletas del jugador y adaptar su dibujo y carga de poses a sistemas personalizados. También permite ocultarlo o desactivar sus cargas dinámicas. Puede entrar en conflicto con parches que modifican los gráficos o paletas del jugador; revisa la advertencia del instalador antes de habilitarla.&lt;br /&gt;
|-&lt;br /&gt;
| Funciones de Yoshi (&amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos de Yoshi manteniendo la organización de sus poses originales. Requiere &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y comparte sus restricciones de compatibilidad.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memoria y optimizaciones ===&lt;br /&gt;
&lt;br /&gt;
Estas opciones reorganizan parte del trabajo del juego para dejar más tiempo disponible para las cargas de gráficos y paletas. NMI es la rutina que realiza las actualizaciones de pantalla durante la pausa entre un frame y el siguiente.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Liberar el área &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;) || En ROMs sin SA-1, evita mantener en RAM ciertos gráficos originales del jugador, Yoshi y animaciones, y permite leerlos desde ROM. Dynamic Xtreme utiliza el espacio recuperado para sus variables internas; no queda libre para usarlo sin reservar. Esta opción no se aplica a ROMs con SA-1.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del control (&amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;) || Mueve el procesamiento del control fuera de NMI para dejar más tiempo disponible para las actualizaciones de pantalla.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del color fijo (&amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI relacionado con la actualización del color fijo que utiliza el juego para sus mezclas de color.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de VRAM de Lunar Magic de Kevin (&amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;) || Integra la optimización de Kevin para las actualizaciones de VRAM de Lunar Magic y mueve parte de su procesamiento fuera de NMI. Utiliza esta versión en lugar del parche original por separado. Una vez instalada, no debe desinstalarse: hacerlo puede dañar el funcionamiento de la ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de la barra de estado (&amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI de la barra de estado original. No es compatible con recursos que la reemplazan o modifican, como barras de estado personalizadas o parches que la eliminan.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para revisar qué opciones pueden entrar en conflicto con otros recursos y qué RAM utiliza el sistema, consulta [[#Compatibilidad|Compatibilidad]].&lt;br /&gt;
&lt;br /&gt;
Algunas funcionalidades necesitan otras: &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; necesita ambas opciones de cambios gráficos y de paletas; y &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guía rápida de instalación:&#039;&#039;&#039; [[es/Dynamic_Xtreme_Quick_Start|Quick Start]]&lt;br /&gt;
&lt;br /&gt;
== Herramientas y Soporte ==&lt;br /&gt;
&lt;br /&gt;
== Archivos y formatos ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Artículo relacionado:&#039;&#039;&#039; [[es/Dynamic_Xtreme_files_and_formats|Archivos y Formatos de Dynamic Xtreme]]&lt;br /&gt;
&lt;br /&gt;
== Guía de creación de sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Para aprender a preparar, programar, cargar y dibujar un sprite dinámico, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites dinámicos con Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
== Dynamic Xtreme con UberASM ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_UberASM_guide|guía de Dynamic Xtreme con UberASM]] muestra cómo reservar paletas, configurar el espacio para sprites dinámicos y el límite de datos por frame, crear animaciones, cambiar gráficos del jugador y aplicar efectos de paleta.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]] explica cómo utilizar las variables, los defines, las rutinas y las macros de Dynamic Xtreme. Incluye los datos que necesita cada llamada, sus resultados y ejemplos de uso para trabajar con poses, dibujo, paletas, efectos de color y transferencias de gráficos, además de las macros de multiplicación y división.&lt;br /&gt;
&lt;br /&gt;
== Funcionamiento interno del sistema ==&lt;br /&gt;
&lt;br /&gt;
== Compatibilidad ==&lt;br /&gt;
&lt;br /&gt;
En general, las funcionalidades que no muestran warnings en el instalador no suelen presentar problemas de incompatibilidad con otros recursos. Estas son:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esto no garantiza que cualquier combinación de recursos funcione: dos códigos todavía pueden utilizar la misma RAM, el mismo espacio de VRAM o modificar la misma rutina del juego. Además, &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, por lo que también debes considerar las restricciones de esta última.&lt;br /&gt;
&lt;br /&gt;
=== Funcionalidades con restricciones de compatibilidad ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad opcional !! Posibles conflictos y qué hacer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; || Puede entrar en conflicto con &#039;&#039;&#039;LX5&#039;s Powerups&#039;&#039;&#039;, &#039;&#039;&#039;Player 8x8 tiles DMAer&#039;&#039;&#039;, &#039;&#039;&#039;Player 32x32&#039;&#039;&#039; y otros sistemas que reemplazan la carga de gráficos o paletas del jugador. &#039;&#039;&#039;Player Revolution&#039;&#039;&#039; sí es compatible. Si tu sistema de jugador necesita esas rutinas originales, deja esta opción deshabilitada; también tendrás que deshabilitar &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; || Depende de &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; y hereda sus restricciones de compatibilidad, aunque no muestre un warning propio. Si otro recurso es incompatible con &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, no puedes evitar ese conflicto habilitando únicamente &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;: debes dejar ambas deshabilitadas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt; || No es compatible con recursos que modifican, reemplazan o eliminan la barra de estado original, como &#039;&#039;&#039;LX5&#039;s DKC Style Status Bar&#039;&#039;&#039;, &#039;&#039;&#039;Minimalistic Status Bar&#039;&#039;&#039; y &#039;&#039;&#039;Nuke Status Bar&#039;&#039;&#039;. Si utilizas uno de ellos, deja esta optimización deshabilitada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt; || Integra el parche de optimización de VRAM de Lunar Magic de Kevin: utiliza esta versión en lugar del parche original por separado. Su warning también indica que &#039;&#039;&#039;no debe desinstalarse después de instalarla&#039;&#039;&#039;, porque hacerlo puede romper el funcionamiento de la ROM. Si necesitas revertirla, restaura una copia de seguridad anterior a su instalación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas funcionalidades son opcionales: puedes dejar deshabilitada la que entra en conflicto y seguir utilizando los demás sistemas de Dynamic Xtreme, respetando sus dependencias. Deshabilitar una opción no deshace los cambios de otro parche ni elimina la restricción de desinstalación de &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Espacios de RAM utilizados ===&lt;br /&gt;
&lt;br /&gt;
Las direcciones principales se configuran en &amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt;, dentro de la carpeta de Dynamic Xtreme. En el repositorio, ese archivo corresponde a &amp;lt;code&amp;gt;DynamicXtremeLibrary/ASM/DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El espacio utilizado depende de las funcionalidades habilitadas y de si la ROM utiliza SA-1. Los siguientes rangos incluyen el primer y el último byte y están calculados con &#039;&#039;&#039;todas las funcionalidades que reservan RAM habilitadas&#039;&#039;&#039;, &amp;lt;code&amp;gt;!VRAMTransferSize = 64&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!CGRAMTransferSize = 64&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuración !! Bloque &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; !! Tamaño !! Bloque &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; !! Tamaño&lt;br /&gt;
|-&lt;br /&gt;
| LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2000–$7E2500&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7E2800–$7E3608&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB440–$7FB940&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7F9C80–$7FAA88&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C000–$40C47E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$047F&amp;lt;/code&amp;gt;: 1151 bytes || &amp;lt;code&amp;gt;$418AFF–$419907&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los dos bloques internos suman &#039;&#039;&#039;4874 bytes en LoROM&#039;&#039;&#039; y &#039;&#039;&#039;4744 bytes en SA-1&#039;&#039;&#039;. La diferencia se debe a los 130 bytes del sistema de dibujo que solo se reservan en LoROM. No se ocupa automáticamente el espacio que queda entre los bloques.&lt;br /&gt;
&lt;br /&gt;
Al deshabilitar una funcionalidad se eliminan sus reservas condicionales y cambian las direcciones posteriores. Aumentar &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; también aumenta el tamaño de sus tablas.&lt;br /&gt;
&lt;br /&gt;
==== Tablas utilizadas por los sprites ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; &#039;&#039;&#039;no son espacios disponibles para escribir variables propias&#039;&#039;&#039;: a partir de esas posiciones se ubican las tablas de sprites de &amp;lt;code&amp;gt;DynamicXSpritesTables.asm&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;MoreSpriteMiscs.asm&amp;lt;/code&amp;gt;. También debes reservarlas si utilizas esos recursos.&lt;br /&gt;
&lt;br /&gt;
Con la misma configuración de la tabla anterior, sus rangos son:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuración !! Tablas desde &amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; !! Tamaño !! Tablas desde &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; !! Tamaño&lt;br /&gt;
|-&lt;br /&gt;
| LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2501–$7E26EC&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7E3609–$7E3824&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB941–$7FBB2C&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7FAC82–$7FAE9D&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C47F–$40C6D8&amp;lt;/code&amp;gt; || 602 bytes || &amp;lt;code&amp;gt;$419908–$419BCD&amp;lt;/code&amp;gt; || 710 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Incluyendo estas tablas, el espacio descrito suma &#039;&#039;&#039;5906 bytes en LoROM&#039;&#039;&#039; y &#039;&#039;&#039;6056 bytes en SA-1&#039;&#039;&#039;. Las tablas se calculan para 12 sprites normales en LoROM y 22 en SA-1, además de los slots de cluster, extended y smoke correspondientes.&lt;br /&gt;
&lt;br /&gt;
Normalmente, &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; comienza justo después del segundo bloque interno. En LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; se coloca por separado mediante &amp;lt;code&amp;gt;!Variables3 = $7FAC82&amp;lt;/code&amp;gt;; por eso sus tablas no empiezan inmediatamente después de &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme también utiliza los espejos existentes del color fijo y de la paleta: &amp;lt;code&amp;gt;$7E0701&amp;lt;/code&amp;gt; (2 bytes) y &amp;lt;code&amp;gt;$7E0703&amp;lt;/code&amp;gt; (512 bytes) en LoROM. En SA-1 sus direcciones declaradas son &amp;lt;code&amp;gt;$406701&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$006703&amp;lt;/code&amp;gt;. No son reservas adicionales dentro de los bloques anteriores ni direcciones libres para tus códigos.&lt;br /&gt;
&lt;br /&gt;
==== Reubicar la RAM si hay un conflicto ====&lt;br /&gt;
&lt;br /&gt;
Si otro recurso utiliza alguno de estos espacios, puedes modificar &#039;&#039;&#039;&amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt;&#039;&#039;&#039; para hacer que Dynamic Xtreme utilice otras zonas disponibles de tu romhack.&lt;br /&gt;
&lt;br /&gt;
* Cambia &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; en la configuración correspondiente a tu ROM: LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, LoROM sin esa opción o SA-1.&lt;br /&gt;
* En LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, revisa también &amp;lt;code&amp;gt;!Variables3&amp;lt;/code&amp;gt;, que determina dónde empiezan las tablas de &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Reserva espacio suficiente para el bloque completo y las tablas de sprites que le siguen. No basta con que la primera dirección esté libre.&lt;br /&gt;
* Respeta el mapa de memoria y los bancos que necesitan las rutinas. No cualquier dirección libre sirve para cualquier acceso.&lt;br /&gt;
* Después de cambiar las direcciones, reinstala Dynamic Xtreme y vuelve a insertar PIXI, UberASM y los demás recursos que utilicen sus defines.&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, Dynamic Xtreme aprovecha el área de RAM que recupera al reubicar los gráficos originales; no la compartas con otros recursos sin comprobar qué parte utiliza. Sin esa opción, las direcciones alternativas pueden coincidir con las de otros recursos habituales. SA-1 utiliza sus propias direcciones y desactiva &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Modifica el archivo de la carpeta &#039;&#039;&#039;ASM&#039;&#039;&#039;, no las copias generadas en &amp;lt;code&amp;gt;ExtraDefines&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;Patch/ExtraDefines&amp;lt;/code&amp;gt;: esas copias se regeneran durante la instalación.&lt;br /&gt;
&lt;br /&gt;
== Recursos hechos con Dynamic Xtreme ==&lt;br /&gt;
&lt;br /&gt;
La mayoría de los recursos desarrollados para Dynamic Xtreme no suelen publicarse en sitios tradicionales como SMW Central debido a que muchos de ellos dependen directamente del framework y sus sistemas avanzados.&lt;br /&gt;
&lt;br /&gt;
En su lugar, los recursos, ejemplos, sistemas y proyectos relacionados con Dynamic Xtreme se encuentran recopilados principalmente en:&lt;br /&gt;
&lt;br /&gt;
https://snestorage.dev&lt;br /&gt;
&lt;br /&gt;
Allí es posible encontrar sprites, sistemas de jugador, efectos gráficos, ejemplos técnicos y otros recursos diseñados específicamente para trabajar con Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
== Conclusión ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es un proyecto orientado a modernizar y simplificar el uso de sistemas dinámicos en Super Mario World, ofreciendo herramientas más flexibles, potentes y fáciles de utilizar sin perder compatibilidad ni control avanzado.&lt;br /&gt;
&lt;br /&gt;
El proyecto continúa evolucionando constantemente con nuevas optimizaciones, formatos y herramientas orientadas tanto a usuarios avanzados como a personas que recién comienzan a trabajar con gráficos dinámicos en SNES.&lt;br /&gt;
&lt;br /&gt;
La intención principal de Dynamic Xtreme es permitir la creación de recursos y sistemas cada vez más complejos, manteniendo al mismo tiempo un workflow más limpio, mantenible y accesible para la comunidad.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21365</id>
		<title>es/Dynamic Xtreme</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21365"/>
		<updated>2026-10-25T00:57:19Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es una herramienta de soporte dinámico avanzada para Super Mario World en el SNES. Desarrollada para la comunidad de ROM hacking, permite realizar cambios gráficos y de paletas en tiempo real durante la ejecución del juego, ampliando considerablemente las capacidades técnicas originales del hardware del SNES.La herramienta se centra en ofrecer un sistema completo y flexible de gráficos dinámicos, con énfasis en el rendimiento y la modularidad. &lt;br /&gt;
&lt;br /&gt;
Entre sus características principales se incluyen:&lt;br /&gt;
* Cambios gráficos y de paleta en tiempo real (on-the-fly).&lt;br /&gt;
* El sistema de Dynamic Sprite más potente y flexible disponible para Super Mario World.&lt;br /&gt;
* Advanced Drawing System, que permite dibujar cualquier frame registrado en pantalla con control total sobre prioridad, capa, desplazamiento (offset) y propiedades.&lt;br /&gt;
* Efectos de paleta avanzados, que incluyen modificación en tiempo real mediante tono (hue), saturación, brillo, fusión de colores, transiciones suaves y control individual de canales RGB y HSL.&lt;br /&gt;
* Reemplazo completo de gráficos y paletas del jugador, compatible con cualquier tamaño de Mario, cualquier cantidad de frames y cualquier estilo de animación.&lt;br /&gt;
* Soporte total para el reemplazo de gráficos de Yoshi.&lt;br /&gt;
* Optimizaciones intensivas en el NMI-handler para maximizar el rendimiento.&lt;br /&gt;
&lt;br /&gt;
Las funciones de Dynamic Xtreme se seleccionan durante la instalación para utilizar solo las que necesita el proyecto. Algunas tienen dependencias, problemas de compatibilidad o restricciones para desinstalarlas; revisa las advertencias de cada opción. La herramienta fue creada con el objetivo de facilitar la implementación de efectos visuales complejos en hacks de Super Mario World manteniendo un alto nivel de compatibilidad y estabilidad.&lt;br /&gt;
&lt;br /&gt;
== Objetivos del proyecto ==&lt;br /&gt;
&lt;br /&gt;
El principal objetivo de Dynamic Xtreme es facilitar el uso de sprites dinámicos y ofrecer un soporte completo para cambios de gráficos, paletas y tilemaps en tiempo real.&lt;br /&gt;
&lt;br /&gt;
El proyecto busca aprovechar al máximo el potencial del SNES sin requerir que el usuario tenga conocimientos avanzados sobre el hardware interno de la consola. Muchos sistemas dinámicos tradicionales suelen ser complejos y dependen fuertemente de conceptos técnicos como VRAM, CGRAM, OAM o DMA. Dynamic Xtreme intenta abstraer gran parte de esa complejidad mediante herramientas y formatos más modernos, legibles y fáciles de utilizar.&lt;br /&gt;
&lt;br /&gt;
Otro de los objetivos principales del proyecto es mantener un alto rendimiento incluso en situaciones visualmente complejas, permitiendo el uso intensivo de gráficos dinámicos, efectos de paletas y sistemas avanzados de renderizado sin comprometer innecesariamente la performance.&lt;br /&gt;
&lt;br /&gt;
Además, Dynamic Xtreme busca que los sprites dinámicos puedan utilizarse de una forma tan natural y sencilla como si fueran sprites normales. La idea es que las personas enfocadas en level design o creación de contenido no necesiten preocuparse constantemente por las limitaciones técnicas internas del sistema y puedan trabajar con recursos dinámicos de forma transparente y práctica.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades ==&lt;br /&gt;
&lt;br /&gt;
Durante la instalación puedes elegir qué funcionalidades habilitar. Los nombres entre paréntesis corresponden a las opciones del instalador y de &amp;lt;code&amp;gt;Settings.json&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Gráficos, poses y paletas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de gráficos (&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;) || Permite cargar gráficos durante el juego. Es la base para las animaciones de tiles, los cambios de gráficos del nivel y las poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de paletas (&amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;) || Permite cargar y administrar paletas durante el juego. Incluye la asignación automática de paletas para que los sprites puedan compartir los mismos colores sin cargarlos varias veces.&lt;br /&gt;
|-&lt;br /&gt;
| Poses dinámicas (&amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;) || Administra el espacio de VRAM como una caché de poses: reutiliza las que ya están cargadas, permite compartirlas entre entidades y elige cuáles reemplazar cuando hace falta espacio. Así evita cargas innecesarias.&lt;br /&gt;
|-&lt;br /&gt;
| Dibujo de poses (&amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;) || Dibuja las poses definidas en archivos DrawInfo, tanto dinámicas como estáticas. Permite controlar sus tiles, posición, volteo, paleta y prioridad de dibujo.&lt;br /&gt;
|-&lt;br /&gt;
| Efectos de paleta (&amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;) || Permite cambiar colores mediante efectos RGB y HSL: teñir paletas, modificar tono, saturación o luminosidad, y realizar transiciones entre paletas. Pueden aplicarse a recursos individuales o como un efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La carga de poses dinámicas y el dibujo son sistemas separados: puedes dibujar una pose estática sin cargar sus gráficos dinámicamente.&lt;br /&gt;
&lt;br /&gt;
=== Jugador y Yoshi ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Funciones del jugador (&amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos y paletas del jugador y adaptar su dibujo y carga de poses a sistemas personalizados. También permite ocultarlo o desactivar sus cargas dinámicas. Puede entrar en conflicto con parches que modifican los gráficos o paletas del jugador; revisa la advertencia del instalador antes de habilitarla.&lt;br /&gt;
|-&lt;br /&gt;
| Funciones de Yoshi (&amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos de Yoshi manteniendo la organización de sus poses originales. Requiere las funciones del jugador.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memoria y optimizaciones ===&lt;br /&gt;
&lt;br /&gt;
Estas opciones reorganizan parte del trabajo del juego para dejar más tiempo disponible para las cargas de gráficos y paletas. NMI es la rutina que realiza las actualizaciones de pantalla durante la pausa entre un frame y el siguiente.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Liberar el área &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;) || En ROMs sin SA-1, evita mantener en RAM ciertos gráficos originales del jugador, Yoshi y animaciones, y permite leerlos desde ROM. Dynamic Xtreme utiliza el espacio recuperado para sus variables internas; no queda libre para usarlo sin reservar. Esta opción no se aplica a ROMs con SA-1.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del control (&amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;) || Mueve el procesamiento del control fuera de NMI para dejar más tiempo disponible para las actualizaciones de pantalla.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del color fijo (&amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI relacionado con la actualización del color fijo que utiliza el juego para sus mezclas de color.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de VRAM de Lunar Magic de Kevin (&amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;) || Integra la optimización de Kevin para las actualizaciones de VRAM de Lunar Magic y mueve parte de su procesamiento fuera de NMI. Utiliza esta versión en lugar del parche original por separado. Una vez instalada, no debe desinstalarse: hacerlo puede dañar el funcionamiento de la ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de la barra de estado (&amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI de la barra de estado original. No es compatible con recursos que la reemplazan o modifican, como barras de estado personalizadas o parches que la eliminan.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para revisar qué opciones pueden entrar en conflicto con otros recursos y qué RAM utiliza el sistema, consulta [[#Compatibilidad|Compatibilidad]].&lt;br /&gt;
&lt;br /&gt;
Algunas funcionalidades necesitan otras: &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; necesita ambas opciones de cambios gráficos y de paletas; y &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guía rápida de instalación:&#039;&#039;&#039; [[es/Dynamic_Xtreme_Quick_Start|Quick Start]]&lt;br /&gt;
&lt;br /&gt;
== Herramientas y Soporte ==&lt;br /&gt;
&lt;br /&gt;
== Archivos y formatos ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Artículo relacionado:&#039;&#039;&#039; [[es/Dynamic_Xtreme_files_and_formats|Archivos y Formatos de Dynamic Xtreme]]&lt;br /&gt;
&lt;br /&gt;
== Guía de creación de sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Para aprender a preparar, programar, cargar y dibujar un sprite dinámico, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites dinámicos con Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
== Dynamic Xtreme con UberASM ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_UberASM_guide|guía de Dynamic Xtreme con UberASM]] muestra cómo reservar paletas, configurar el espacio para sprites dinámicos y el límite de datos por frame, crear animaciones, cambiar gráficos del jugador y aplicar efectos de paleta.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]] explica cómo utilizar las variables, los defines, las rutinas y las macros de Dynamic Xtreme. Incluye los datos que necesita cada llamada, sus resultados y ejemplos de uso para trabajar con poses, dibujo, paletas, efectos de color y transferencias de gráficos, además de las macros de multiplicación y división.&lt;br /&gt;
&lt;br /&gt;
== Funcionamiento interno del sistema ==&lt;br /&gt;
&lt;br /&gt;
== Compatibilidad ==&lt;br /&gt;
&lt;br /&gt;
En general, las funcionalidades que no muestran warnings en el instalador no suelen presentar problemas de incompatibilidad con otros recursos. Estas son:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esto no garantiza que cualquier combinación de recursos funcione: dos códigos todavía pueden utilizar la misma RAM, el mismo espacio de VRAM o modificar la misma rutina del juego. Además, &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, por lo que también debes considerar las restricciones de esta última.&lt;br /&gt;
&lt;br /&gt;
=== Funcionalidades con advertencias ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad opcional !! Posibles conflictos y qué hacer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; || Puede entrar en conflicto con &#039;&#039;&#039;LX5&#039;s Powerups&#039;&#039;&#039;, &#039;&#039;&#039;Player 8x8 tiles DMAer&#039;&#039;&#039;, &#039;&#039;&#039;Player 32x32&#039;&#039;&#039; y otros sistemas que reemplazan la carga de gráficos o paletas del jugador. &#039;&#039;&#039;Player Revolution&#039;&#039;&#039; sí es compatible. Si tu sistema de jugador necesita esas rutinas originales, deja esta opción deshabilitada; también tendrás que deshabilitar &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt; || No es compatible con recursos que modifican, reemplazan o eliminan la barra de estado original, como &#039;&#039;&#039;LX5&#039;s DKC Style Status Bar&#039;&#039;&#039;, &#039;&#039;&#039;Minimalistic Status Bar&#039;&#039;&#039; y &#039;&#039;&#039;Nuke Status Bar&#039;&#039;&#039;. Si utilizas uno de ellos, deja esta optimización deshabilitada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt; || Integra el parche de optimización de VRAM de Lunar Magic de Kevin: utiliza esta versión en lugar del parche original por separado. Su warning también indica que &#039;&#039;&#039;no debe desinstalarse después de instalarla&#039;&#039;&#039;, porque hacerlo puede romper el funcionamiento de la ROM. Si necesitas revertirla, restaura una copia de seguridad anterior a su instalación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Estas funcionalidades son opcionales: puedes dejar deshabilitada la que entra en conflicto y seguir utilizando los demás sistemas de Dynamic Xtreme, respetando sus dependencias. Deshabilitar una opción no deshace los cambios de otro parche ni elimina la restricción de desinstalación de &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Espacios de RAM utilizados ===&lt;br /&gt;
&lt;br /&gt;
Las direcciones principales se configuran en &amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt;, dentro de la carpeta de Dynamic Xtreme. En el repositorio, ese archivo corresponde a &amp;lt;code&amp;gt;DynamicXtremeLibrary/ASM/DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El espacio utilizado depende de las funcionalidades habilitadas y de si la ROM utiliza SA-1. Los siguientes rangos incluyen el primer y el último byte y están calculados con &#039;&#039;&#039;todas las funcionalidades que reservan RAM habilitadas&#039;&#039;&#039;, &amp;lt;code&amp;gt;!VRAMTransferSize = 64&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!CGRAMTransferSize = 64&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuración !! Bloque &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; !! Tamaño !! Bloque &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; !! Tamaño&lt;br /&gt;
|-&lt;br /&gt;
| LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2000–$7E2500&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7E2800–$7E3608&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB440–$7FB940&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0501&amp;lt;/code&amp;gt;: 1281 bytes || &amp;lt;code&amp;gt;$7F9C80–$7FAA88&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C000–$40C47E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$047F&amp;lt;/code&amp;gt;: 1151 bytes || &amp;lt;code&amp;gt;$418AFF–$419907&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0E09&amp;lt;/code&amp;gt;: 3593 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los dos bloques internos suman &#039;&#039;&#039;4874 bytes en LoROM&#039;&#039;&#039; y &#039;&#039;&#039;4744 bytes en SA-1&#039;&#039;&#039;. La diferencia se debe a los 130 bytes del sistema de dibujo que solo se reservan en LoROM. No se ocupa automáticamente el espacio que queda entre los bloques.&lt;br /&gt;
&lt;br /&gt;
Al deshabilitar una funcionalidad se eliminan sus reservas condicionales y cambian las direcciones posteriores. Aumentar &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; también aumenta el tamaño de sus tablas.&lt;br /&gt;
&lt;br /&gt;
==== Tablas utilizadas por los sprites ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; &#039;&#039;&#039;no son espacios disponibles para escribir variables propias&#039;&#039;&#039;: a partir de esas posiciones se ubican las tablas de sprites de &amp;lt;code&amp;gt;DynamicXSpritesTables.asm&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;MoreSpriteMiscs.asm&amp;lt;/code&amp;gt;. También debes reservarlas si utilizas esos recursos.&lt;br /&gt;
&lt;br /&gt;
Con la misma configuración de la tabla anterior, sus rangos son:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Configuración !! Tablas desde &amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; !! Tamaño !! Tablas desde &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; !! Tamaño&lt;br /&gt;
|-&lt;br /&gt;
| LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2501–$7E26EC&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7E3609–$7E3824&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7FB941–$7FBB2C&amp;lt;/code&amp;gt; || 492 bytes || &amp;lt;code&amp;gt;$7FAC82–$7FAE9D&amp;lt;/code&amp;gt; || 540 bytes&lt;br /&gt;
|-&lt;br /&gt;
| SA-1 || &amp;lt;code&amp;gt;$40C47F–$40C6D8&amp;lt;/code&amp;gt; || 602 bytes || &amp;lt;code&amp;gt;$419908–$419BCD&amp;lt;/code&amp;gt; || 710 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Incluyendo estas tablas, el espacio descrito suma &#039;&#039;&#039;5906 bytes en LoROM&#039;&#039;&#039; y &#039;&#039;&#039;6056 bytes en SA-1&#039;&#039;&#039;. Las tablas se calculan para 12 sprites normales en LoROM y 22 en SA-1, además de los slots de cluster, extended y smoke correspondientes.&lt;br /&gt;
&lt;br /&gt;
Normalmente, &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; comienza justo después del segundo bloque interno. En LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt; se coloca por separado mediante &amp;lt;code&amp;gt;!Variables3 = $7FAC82&amp;lt;/code&amp;gt;; por eso sus tablas no empiezan inmediatamente después de &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme también utiliza los espejos existentes del color fijo y de la paleta: &amp;lt;code&amp;gt;$7E0701&amp;lt;/code&amp;gt; (2 bytes) y &amp;lt;code&amp;gt;$7E0703&amp;lt;/code&amp;gt; (512 bytes) en LoROM. En SA-1 sus direcciones declaradas son &amp;lt;code&amp;gt;$406701&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$006703&amp;lt;/code&amp;gt;. No son reservas adicionales dentro de los bloques anteriores ni direcciones libres para tus códigos.&lt;br /&gt;
&lt;br /&gt;
==== Reubicar la RAM si hay un conflicto ====&lt;br /&gt;
&lt;br /&gt;
Si otro recurso utiliza alguno de estos espacios, puedes modificar &#039;&#039;&#039;&amp;lt;code&amp;gt;ASM/DXDefines.asm&amp;lt;/code&amp;gt;&#039;&#039;&#039; para hacer que Dynamic Xtreme utilice otras zonas disponibles de tu romhack.&lt;br /&gt;
&lt;br /&gt;
* Cambia &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt; en la configuración correspondiente a tu ROM: LoROM con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, LoROM sin esa opción o SA-1.&lt;br /&gt;
* En LoROM sin &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, revisa también &amp;lt;code&amp;gt;!Variables3&amp;lt;/code&amp;gt;, que determina dónde empiezan las tablas de &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Reserva espacio suficiente para el bloque completo y las tablas de sprites que le siguen. No basta con que la primera dirección esté libre.&lt;br /&gt;
* Respeta el mapa de memoria y los bancos que necesitan las rutinas. No cualquier dirección libre sirve para cualquier acceso.&lt;br /&gt;
* Después de cambiar las direcciones, reinstala Dynamic Xtreme y vuelve a insertar PIXI, UberASM y los demás recursos que utilicen sus defines.&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, Dynamic Xtreme aprovecha el área de RAM que recupera al reubicar los gráficos originales; no la compartas con otros recursos sin comprobar qué parte utiliza. Sin esa opción, las direcciones alternativas pueden coincidir con las de otros recursos habituales. SA-1 utiliza sus propias direcciones y desactiva &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Modifica el archivo de la carpeta &#039;&#039;&#039;ASM&#039;&#039;&#039;, no las copias generadas en &amp;lt;code&amp;gt;ExtraDefines&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;Patch/ExtraDefines&amp;lt;/code&amp;gt;: esas copias se regeneran durante la instalación.&lt;br /&gt;
&lt;br /&gt;
== Recursos hechos con Dynamic Xtreme ==&lt;br /&gt;
&lt;br /&gt;
La mayoría de los recursos desarrollados para Dynamic Xtreme no suelen publicarse en sitios tradicionales como SMW Central debido a que muchos de ellos dependen directamente del framework y sus sistemas avanzados.&lt;br /&gt;
&lt;br /&gt;
En su lugar, los recursos, ejemplos, sistemas y proyectos relacionados con Dynamic Xtreme se encuentran recopilados principalmente en:&lt;br /&gt;
&lt;br /&gt;
https://snestorage.dev&lt;br /&gt;
&lt;br /&gt;
Allí es posible encontrar sprites, sistemas de jugador, efectos gráficos, ejemplos técnicos y otros recursos diseñados específicamente para trabajar con Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
== Conclusión ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es un proyecto orientado a modernizar y simplificar el uso de sistemas dinámicos en Super Mario World, ofreciendo herramientas más flexibles, potentes y fáciles de utilizar sin perder compatibilidad ni control avanzado.&lt;br /&gt;
&lt;br /&gt;
El proyecto continúa evolucionando constantemente con nuevas optimizaciones, formatos y herramientas orientadas tanto a usuarios avanzados como a personas que recién comienzan a trabajar con gráficos dinámicos en SNES.&lt;br /&gt;
&lt;br /&gt;
La intención principal de Dynamic Xtreme es permitir la creación de recursos y sistemas cada vez más complejos, manteniendo al mismo tiempo un workflow más limpio, mantenible y accesible para la comunidad.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21364</id>
		<title>es/Dynamic Xtreme</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21364"/>
		<updated>2026-10-24T23:12:40Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es una herramienta de soporte dinámico avanzada para Super Mario World en el SNES. Desarrollada para la comunidad de ROM hacking, permite realizar cambios gráficos y de paletas en tiempo real durante la ejecución del juego, ampliando considerablemente las capacidades técnicas originales del hardware del SNES.La herramienta se centra en ofrecer un sistema completo y flexible de gráficos dinámicos, con énfasis en el rendimiento y la modularidad. &lt;br /&gt;
&lt;br /&gt;
Entre sus características principales se incluyen:&lt;br /&gt;
* Cambios gráficos y de paleta en tiempo real (on-the-fly).&lt;br /&gt;
* El sistema de Dynamic Sprite más potente y flexible disponible para Super Mario World.&lt;br /&gt;
* Advanced Drawing System, que permite dibujar cualquier frame registrado en pantalla con control total sobre prioridad, capa, desplazamiento (offset) y propiedades.&lt;br /&gt;
* Efectos de paleta avanzados, que incluyen modificación en tiempo real mediante tono (hue), saturación, brillo, fusión de colores, transiciones suaves y control individual de canales RGB y HSL.&lt;br /&gt;
* Reemplazo completo de gráficos y paletas del jugador, compatible con cualquier tamaño de Mario, cualquier cantidad de frames y cualquier estilo de animación.&lt;br /&gt;
* Soporte total para el reemplazo de gráficos de Yoshi.&lt;br /&gt;
* Optimizaciones intensivas en el NMI-handler para maximizar el rendimiento.&lt;br /&gt;
&lt;br /&gt;
Las funciones de Dynamic Xtreme se seleccionan durante la instalación para utilizar solo las que necesita el proyecto. Algunas tienen dependencias, problemas de compatibilidad o restricciones para desinstalarlas; revisa las advertencias de cada opción. La herramienta fue creada con el objetivo de facilitar la implementación de efectos visuales complejos en hacks de Super Mario World manteniendo un alto nivel de compatibilidad y estabilidad.&lt;br /&gt;
&lt;br /&gt;
== Objetivos del proyecto ==&lt;br /&gt;
&lt;br /&gt;
El principal objetivo de Dynamic Xtreme es facilitar el uso de sprites dinámicos y ofrecer un soporte completo para cambios de gráficos, paletas y tilemaps en tiempo real.&lt;br /&gt;
&lt;br /&gt;
El proyecto busca aprovechar al máximo el potencial del SNES sin requerir que el usuario tenga conocimientos avanzados sobre el hardware interno de la consola. Muchos sistemas dinámicos tradicionales suelen ser complejos y dependen fuertemente de conceptos técnicos como VRAM, CGRAM, OAM o DMA. Dynamic Xtreme intenta abstraer gran parte de esa complejidad mediante herramientas y formatos más modernos, legibles y fáciles de utilizar.&lt;br /&gt;
&lt;br /&gt;
Otro de los objetivos principales del proyecto es mantener un alto rendimiento incluso en situaciones visualmente complejas, permitiendo el uso intensivo de gráficos dinámicos, efectos de paletas y sistemas avanzados de renderizado sin comprometer innecesariamente la performance.&lt;br /&gt;
&lt;br /&gt;
Además, Dynamic Xtreme busca que los sprites dinámicos puedan utilizarse de una forma tan natural y sencilla como si fueran sprites normales. La idea es que las personas enfocadas en level design o creación de contenido no necesiten preocuparse constantemente por las limitaciones técnicas internas del sistema y puedan trabajar con recursos dinámicos de forma transparente y práctica.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades ==&lt;br /&gt;
&lt;br /&gt;
Durante la instalación puedes elegir qué funcionalidades habilitar. Los nombres entre paréntesis corresponden a las opciones del instalador y de &amp;lt;code&amp;gt;Settings.json&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Gráficos, poses y paletas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de gráficos (&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;) || Permite cargar gráficos durante el juego. Es la base para las animaciones de tiles, los cambios de gráficos del nivel y las poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de paletas (&amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;) || Permite cargar y administrar paletas durante el juego. Incluye la asignación automática de paletas para que los sprites puedan compartir los mismos colores sin cargarlos varias veces.&lt;br /&gt;
|-&lt;br /&gt;
| Poses dinámicas (&amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;) || Administra el espacio de VRAM como una caché de poses: reutiliza las que ya están cargadas, permite compartirlas entre entidades y elige cuáles reemplazar cuando hace falta espacio. Así evita cargas innecesarias.&lt;br /&gt;
|-&lt;br /&gt;
| Dibujo de poses (&amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;) || Dibuja las poses definidas en archivos DrawInfo, tanto dinámicas como estáticas. Permite controlar sus tiles, posición, volteo, paleta y prioridad de dibujo.&lt;br /&gt;
|-&lt;br /&gt;
| Efectos de paleta (&amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;) || Permite cambiar colores mediante efectos RGB y HSL: teñir paletas, modificar tono, saturación o luminosidad, y realizar transiciones entre paletas. Pueden aplicarse a recursos individuales o como un efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La carga de poses dinámicas y el dibujo son sistemas separados: puedes dibujar una pose estática sin cargar sus gráficos dinámicamente.&lt;br /&gt;
&lt;br /&gt;
=== Jugador y Yoshi ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Funciones del jugador (&amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos y paletas del jugador y adaptar su dibujo y carga de poses a sistemas personalizados. También permite ocultarlo o desactivar sus cargas dinámicas. Puede entrar en conflicto con parches que modifican los gráficos o paletas del jugador; revisa la advertencia del instalador antes de habilitarla.&lt;br /&gt;
|-&lt;br /&gt;
| Funciones de Yoshi (&amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos de Yoshi manteniendo la organización de sus poses originales. Requiere las funciones del jugador.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memoria y optimizaciones ===&lt;br /&gt;
&lt;br /&gt;
Estas opciones reorganizan parte del trabajo del juego para dejar más tiempo disponible para las cargas de gráficos y paletas. NMI es la rutina que realiza las actualizaciones de pantalla durante la pausa entre un frame y el siguiente.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Liberar el área &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;) || En ROMs sin SA-1, evita mantener en RAM ciertos gráficos originales del jugador, Yoshi y animaciones, y permite leerlos desde ROM. Dynamic Xtreme utiliza el espacio recuperado para sus variables internas; no queda libre para usarlo sin reservar. Esta opción no se aplica a ROMs con SA-1.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del control (&amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;) || Mueve el procesamiento del control fuera de NMI para dejar más tiempo disponible para las actualizaciones de pantalla.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del color fijo (&amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI relacionado con la actualización del color fijo que utiliza el juego para sus mezclas de color.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de VRAM de Lunar Magic de Kevin (&amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;) || Integra la optimización de Kevin para las actualizaciones de VRAM de Lunar Magic y mueve parte de su procesamiento fuera de NMI. Utiliza esta versión en lugar del parche original por separado. Una vez instalada, no debe desinstalarse: hacerlo puede dañar el funcionamiento de la ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de la barra de estado (&amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI de la barra de estado original. No es compatible con recursos que la reemplazan o modifican, como barras de estado personalizadas o parches que la eliminan.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Compatibilidad con otros recursos ===&lt;br /&gt;
&lt;br /&gt;
Estas opciones requieren especial atención si tu ROM ya utiliza otros parches:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Advertencia de compatibilidad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; || Tiene problemas de compatibilidad con recursos que modifican los gráficos o paletas del jugador, como &#039;&#039;&#039;LX5&#039;s Powerups&#039;&#039;&#039;, &#039;&#039;&#039;Player 8x8 tiles DMAer&#039;&#039;&#039; y &#039;&#039;&#039;Player 32x32&#039;&#039;&#039;. &#039;&#039;&#039;Player Revolution&#039;&#039;&#039; sí es compatible. Si utilizas otro sistema de jugador, comprueba su compatibilidad antes de habilitar esta opción.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt; || No la habilites si utilizas un recurso que modifica, reemplaza o elimina la barra de estado original. Entre los incompatibles están &#039;&#039;&#039;LX5&#039;s DKC Style Status Bar&#039;&#039;&#039;, &#039;&#039;&#039;Minimalistic Status Bar&#039;&#039;&#039; y &#039;&#039;&#039;Nuke Status Bar&#039;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt; || Esta opción sustituye el parche original de optimización de VRAM de Lunar Magic de Kevin: utiliza la versión integrada, no ambas por separado. Además, una vez instalada no debe desinstalarse, porque hacerlo puede romper el funcionamiento del juego.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;, por lo que también debes tener en cuenta las restricciones de esta última. En cuanto a &amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;, no asignes su espacio a otros recursos: Dynamic Xtreme lo utiliza para sus propias variables.&lt;br /&gt;
&lt;br /&gt;
Estas advertencias no son una garantía de compatibilidad para cualquier otro recurso. Antes de activar una opción, revisa también los requisitos de los parches que ya utiliza tu ROM.&lt;br /&gt;
&lt;br /&gt;
Algunas funcionalidades necesitan otras: &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; necesita ambas opciones de cambios gráficos y de paletas; y &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guía rápida de instalación:&#039;&#039;&#039; [[es/Dynamic_Xtreme_Quick_Start|Quick Start]]&lt;br /&gt;
&lt;br /&gt;
== Herramientas y Soporte ==&lt;br /&gt;
&lt;br /&gt;
== Archivos y formatos ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Artículo relacionado:&#039;&#039;&#039; [[es/Dynamic_Xtreme_files_and_formats|Archivos y Formatos de Dynamic Xtreme]]&lt;br /&gt;
&lt;br /&gt;
== Guía de creación de sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Para aprender a preparar, programar, cargar y dibujar un sprite dinámico, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites dinámicos con Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
== Dynamic Xtreme con UberASM ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_UberASM_guide|guía de Dynamic Xtreme con UberASM]] muestra cómo reservar paletas, configurar el espacio para sprites dinámicos y el límite de datos por frame, crear animaciones, cambiar gráficos del jugador y aplicar efectos de paleta.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]] explica cómo utilizar las variables, los defines, las rutinas y las macros de Dynamic Xtreme. Incluye los datos que necesita cada llamada, sus resultados y ejemplos de uso para trabajar con poses, dibujo, paletas, efectos de color y transferencias de gráficos, además de las macros de multiplicación y división.&lt;br /&gt;
&lt;br /&gt;
== Funcionamiento interno del sistema ==&lt;br /&gt;
&lt;br /&gt;
== Compatibilidad ==&lt;br /&gt;
&lt;br /&gt;
== Recursos hechos con Dynamic Xtreme ==&lt;br /&gt;
&lt;br /&gt;
La mayoría de los recursos desarrollados para Dynamic Xtreme no suelen publicarse en sitios tradicionales como SMW Central debido a que muchos de ellos dependen directamente del framework y sus sistemas avanzados.&lt;br /&gt;
&lt;br /&gt;
En su lugar, los recursos, ejemplos, sistemas y proyectos relacionados con Dynamic Xtreme se encuentran recopilados principalmente en:&lt;br /&gt;
&lt;br /&gt;
https://snestorage.dev&lt;br /&gt;
&lt;br /&gt;
Allí es posible encontrar sprites, sistemas de jugador, efectos gráficos, ejemplos técnicos y otros recursos diseñados específicamente para trabajar con Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
== Conclusión ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es un proyecto orientado a modernizar y simplificar el uso de sistemas dinámicos en Super Mario World, ofreciendo herramientas más flexibles, potentes y fáciles de utilizar sin perder compatibilidad ni control avanzado.&lt;br /&gt;
&lt;br /&gt;
El proyecto continúa evolucionando constantemente con nuevas optimizaciones, formatos y herramientas orientadas tanto a usuarios avanzados como a personas que recién comienzan a trabajar con gráficos dinámicos en SNES.&lt;br /&gt;
&lt;br /&gt;
La intención principal de Dynamic Xtreme es permitir la creación de recursos y sistemas cada vez más complejos, manteniendo al mismo tiempo un workflow más limpio, mantenible y accesible para la comunidad.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21363</id>
		<title>es/Dynamic Xtreme</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21363"/>
		<updated>2026-10-24T23:07:47Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es una herramienta de soporte dinámico avanzada para Super Mario World en el SNES. Desarrollada para la comunidad de ROM hacking, permite realizar cambios gráficos y de paletas en tiempo real durante la ejecución del juego, ampliando considerablemente las capacidades técnicas originales del hardware del SNES.La herramienta se centra en ofrecer un sistema completo y flexible de gráficos dinámicos, con énfasis en el rendimiento y la modularidad. &lt;br /&gt;
&lt;br /&gt;
Entre sus características principales se incluyen:&lt;br /&gt;
* Cambios gráficos y de paleta en tiempo real (on-the-fly).&lt;br /&gt;
* El sistema de Dynamic Sprite más potente y flexible disponible para Super Mario World.&lt;br /&gt;
* Advanced Drawing System, que permite dibujar cualquier frame registrado en pantalla con control total sobre prioridad, capa, desplazamiento (offset) y propiedades.&lt;br /&gt;
* Efectos de paleta avanzados, que incluyen modificación en tiempo real mediante tono (hue), saturación, brillo, fusión de colores, transiciones suaves y control individual de canales RGB y HSL.&lt;br /&gt;
* Reemplazo completo de gráficos y paletas del jugador, compatible con cualquier tamaño de Mario, cualquier cantidad de frames y cualquier estilo de animación.&lt;br /&gt;
* Soporte total para el reemplazo de gráficos de Yoshi.&lt;br /&gt;
* Optimizaciones intensivas en el NMI-handler para maximizar el rendimiento.&lt;br /&gt;
&lt;br /&gt;
Todas las funciones de Dynamic Xtreme son completamente opcionales y modulares, lo que permite instalar o desinstalar cualquiera de ellas en cualquier momento sin generar código innecesario ni conflictos con otras herramientas.La herramienta fue creada con el objetivo de facilitar la implementación de efectos visuales complejos en hacks de Super Mario World manteniendo un alto nivel de compatibilidad y estabilidad.&lt;br /&gt;
&lt;br /&gt;
== Objetivos del proyecto ==&lt;br /&gt;
&lt;br /&gt;
El principal objetivo de Dynamic Xtreme es facilitar el uso de sprites dinámicos y ofrecer un soporte completo para cambios de gráficos, paletas y tilemaps en tiempo real.&lt;br /&gt;
&lt;br /&gt;
El proyecto busca aprovechar al máximo el potencial del SNES sin requerir que el usuario tenga conocimientos avanzados sobre el hardware interno de la consola. Muchos sistemas dinámicos tradicionales suelen ser complejos y dependen fuertemente de conceptos técnicos como VRAM, CGRAM, OAM o DMA. Dynamic Xtreme intenta abstraer gran parte de esa complejidad mediante herramientas y formatos más modernos, legibles y fáciles de utilizar.&lt;br /&gt;
&lt;br /&gt;
Otro de los objetivos principales del proyecto es mantener un alto rendimiento incluso en situaciones visualmente complejas, permitiendo el uso intensivo de gráficos dinámicos, efectos de paletas y sistemas avanzados de renderizado sin comprometer innecesariamente la performance.&lt;br /&gt;
&lt;br /&gt;
Además, Dynamic Xtreme busca que los sprites dinámicos puedan utilizarse de una forma tan natural y sencilla como si fueran sprites normales. La idea es que las personas enfocadas en level design o creación de contenido no necesiten preocuparse constantemente por las limitaciones técnicas internas del sistema y puedan trabajar con recursos dinámicos de forma transparente y práctica.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades ==&lt;br /&gt;
&lt;br /&gt;
Durante la instalación puedes elegir qué funcionalidades habilitar. Los nombres entre paréntesis corresponden a las opciones del instalador y de &amp;lt;code&amp;gt;Settings.json&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Gráficos, poses y paletas ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de gráficos (&amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;) || Permite cargar gráficos durante el juego. Es la base para las animaciones de tiles, los cambios de gráficos del nivel y las poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| Cambios de paletas (&amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;) || Permite cargar y administrar paletas durante el juego. Incluye la asignación automática de paletas para que los sprites puedan compartir los mismos colores sin cargarlos varias veces.&lt;br /&gt;
|-&lt;br /&gt;
| Poses dinámicas (&amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt;) || Administra el espacio de VRAM como una caché de poses: reutiliza las que ya están cargadas, permite compartirlas entre entidades y elige cuáles reemplazar cuando hace falta espacio. Así evita cargas innecesarias.&lt;br /&gt;
|-&lt;br /&gt;
| Dibujo de poses (&amp;lt;code&amp;gt;DrawingSystem&amp;lt;/code&amp;gt;) || Dibuja las poses definidas en archivos DrawInfo, tanto dinámicas como estáticas. Permite controlar sus tiles, posición, volteo, paleta y prioridad de dibujo.&lt;br /&gt;
|-&lt;br /&gt;
| Efectos de paleta (&amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt;) || Permite cambiar colores mediante efectos RGB y HSL: teñir paletas, modificar tono, saturación o luminosidad, y realizar transiciones entre paletas. Pueden aplicarse a recursos individuales o como un efecto global.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La carga de poses dinámicas y el dibujo son sistemas separados: puedes dibujar una pose estática sin cargar sus gráficos dinámicamente.&lt;br /&gt;
&lt;br /&gt;
=== Jugador y Yoshi ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Funciones del jugador (&amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos y paletas del jugador y adaptar su dibujo y carga de poses a sistemas personalizados. También permite ocultarlo o desactivar sus cargas dinámicas. Puede entrar en conflicto con parches que modifican los gráficos o paletas del jugador; revisa la advertencia del instalador antes de habilitarla.&lt;br /&gt;
|-&lt;br /&gt;
| Funciones de Yoshi (&amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt;) || Permite cambiar los gráficos de Yoshi manteniendo la organización de sus poses originales. Requiere las funciones del jugador.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memoria y optimizaciones ===&lt;br /&gt;
&lt;br /&gt;
Estas opciones reorganizan parte del trabajo del juego para dejar más tiempo disponible para las cargas de gráficos y paletas. NMI es la rutina que realiza las actualizaciones de pantalla durante la pausa entre un frame y el siguiente.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funcionalidad !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| Liberar el área &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;Free7E2000&amp;lt;/code&amp;gt;) || En ROMs sin SA-1, evita mantener en RAM ciertos gráficos originales del jugador, Yoshi y animaciones, y permite leerlos desde ROM. Dynamic Xtreme utiliza el espacio recuperado para sus variables internas; no queda libre para usarlo sin reservar. Esta opción no se aplica a ROMs con SA-1.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del control (&amp;lt;code&amp;gt;ControllerOptimization&amp;lt;/code&amp;gt;) || Mueve el procesamiento del control fuera de NMI para dejar más tiempo disponible para las actualizaciones de pantalla.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización del color fijo (&amp;lt;code&amp;gt;FixedColorOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI relacionado con la actualización del color fijo que utiliza el juego para sus mezclas de color.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de VRAM de Lunar Magic de Kevin (&amp;lt;code&amp;gt;KevinLMVRAMOptimization&amp;lt;/code&amp;gt;) || Integra la optimización de Kevin para las actualizaciones de VRAM de Lunar Magic y mueve parte de su procesamiento fuera de NMI. Utiliza esta versión en lugar del parche original por separado. Una vez instalada, no debe desinstalarse: hacerlo puede dañar el funcionamiento de la ROM.&lt;br /&gt;
|-&lt;br /&gt;
| Optimización de la barra de estado (&amp;lt;code&amp;gt;StatusBarOptimization&amp;lt;/code&amp;gt;) || Reduce el trabajo de NMI de la barra de estado original. No es compatible con recursos que la reemplazan o modifican, como barras de estado personalizadas o parches que la eliminan.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Algunas funcionalidades necesitan otras: &amp;lt;code&amp;gt;DynamicPoses&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;GraphicsChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PalettesEffects&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PalettesChange&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; necesita ambas opciones de cambios gráficos y de paletas; y &amp;lt;code&amp;gt;YoshiFeatures&amp;lt;/code&amp;gt; requiere &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guía rápida de instalación:&#039;&#039;&#039; [[es/Dynamic_Xtreme_Quick_Start|Quick Start]]&lt;br /&gt;
&lt;br /&gt;
== Herramientas y Soporte ==&lt;br /&gt;
&lt;br /&gt;
== Archivos y formatos ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Artículo relacionado:&#039;&#039;&#039; [[es/Dynamic_Xtreme_files_and_formats|Archivos y Formatos de Dynamic Xtreme]]&lt;br /&gt;
&lt;br /&gt;
== Guía de creación de sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Para aprender a preparar, programar, cargar y dibujar un sprite dinámico, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites dinámicos con Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
== Dynamic Xtreme con UberASM ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_UberASM_guide|guía de Dynamic Xtreme con UberASM]] muestra cómo reservar paletas, configurar el espacio para sprites dinámicos y el límite de datos por frame, crear animaciones, cambiar gráficos del jugador y aplicar efectos de paleta.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]] explica cómo utilizar las variables, los defines, las rutinas y las macros de Dynamic Xtreme. Incluye los datos que necesita cada llamada, sus resultados y ejemplos de uso para trabajar con poses, dibujo, paletas, efectos de color y transferencias de gráficos, además de las macros de multiplicación y división.&lt;br /&gt;
&lt;br /&gt;
== Funcionamiento interno del sistema ==&lt;br /&gt;
&lt;br /&gt;
== Compatibilidad ==&lt;br /&gt;
&lt;br /&gt;
== Recursos hechos con Dynamic Xtreme ==&lt;br /&gt;
&lt;br /&gt;
La mayoría de los recursos desarrollados para Dynamic Xtreme no suelen publicarse en sitios tradicionales como SMW Central debido a que muchos de ellos dependen directamente del framework y sus sistemas avanzados.&lt;br /&gt;
&lt;br /&gt;
En su lugar, los recursos, ejemplos, sistemas y proyectos relacionados con Dynamic Xtreme se encuentran recopilados principalmente en:&lt;br /&gt;
&lt;br /&gt;
https://snestorage.dev&lt;br /&gt;
&lt;br /&gt;
Allí es posible encontrar sprites, sistemas de jugador, efectos gráficos, ejemplos técnicos y otros recursos diseñados específicamente para trabajar con Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
== Conclusión ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es un proyecto orientado a modernizar y simplificar el uso de sistemas dinámicos en Super Mario World, ofreciendo herramientas más flexibles, potentes y fáciles de utilizar sin perder compatibilidad ni control avanzado.&lt;br /&gt;
&lt;br /&gt;
El proyecto continúa evolucionando constantemente con nuevas optimizaciones, formatos y herramientas orientadas tanto a usuarios avanzados como a personas que recién comienzan a trabajar con gráficos dinámicos en SNES.&lt;br /&gt;
&lt;br /&gt;
La intención principal de Dynamic Xtreme es permitir la creación de recursos y sistemas cada vez más complejos, manteniendo al mismo tiempo un workflow más limpio, mantenible y accesible para la comunidad.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21362</id>
		<title>es/Dynamic Xtreme UberASM guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21362"/>
		<updated>2026-10-24T22:54:37Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_UberASM_guide}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo utilizar Dynamic Xtreme desde UberASM para configurar los recursos de un nivel y crear cambios de gráficos y colores durante el juego. Se incluyen ejemplos para reservar paletas, elegir el espacio disponible para sprites dinámicos, crear animaciones y modificar los gráficos del jugador.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Tener UberASMTool instalado y configurado para insertar códigos en tu ROM.&lt;br /&gt;
* Tener Dynamic Xtreme instalado con las funciones necesarias para el ejemplo que quieras utilizar. Consulta la [[es/Dynamic_Xtreme_Quick_Start|guía de inicio rápido]] para su instalación.&lt;br /&gt;
&lt;br /&gt;
Para consultar los parámetros de una llamada o el uso de una variable, utiliza la [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]].&lt;br /&gt;
&lt;br /&gt;
== Preparar los ejemplos ==&lt;br /&gt;
&lt;br /&gt;
Cada ejemplo es independiente. Guarda el código de nivel en la carpeta correspondiente de UberASMTool y añádelo a su lista. Si reúnes varios ejemplos en un archivo, combina sus bloques &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; para no repetir las mismas etiquetas.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt; prepara datos durante la carga del nivel. Se utiliza aquí para reservar paletas antes de que las reclamen los sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; prepara las opciones al entrar al nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; ejecuta el código durante el juego, una vez por frame.&lt;br /&gt;
&lt;br /&gt;
Los defines y macros de Dynamic Xtreme deben estar disponibles en UberASMTool mediante la integración realizada durante la instalación. Si utilizas gráficos, paletas o efectos adicionales, decláralos en el ASM mediante los includes correspondientes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MyResources.dynamicinfo&amp;quot;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/MyEffect.paleffect&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las rutas son relativas al ASM. Incluye únicamente los archivos que utiliza tu ejemplo. También puedes usar las carpetas tradicionales de Dynamic Xtreme, como se explica en [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
&lt;br /&gt;
Después de añadir o modificar estos recursos, instala primero Dynamic Xtreme y después UberASMTool. Si solo cambias la lógica del ASM, basta con volver a ejecutar UberASMTool.&lt;br /&gt;
&lt;br /&gt;
Los nombres &amp;lt;code&amp;gt;RAM_LIBRE_...&amp;lt;/code&amp;gt; de los ejemplos son marcadores: reemplázalos por direcciones de RAM libre antes de insertar el código. No son defines de Dynamic Xtreme. Reserva la cantidad de bytes indicada y utiliza direcciones distintas para variables que deban coexistir. Comprueba que no las utilicen el juego, Dynamic Xtreme, Lunar Magic u otros recursos; que una dirección esté libre en SMW original no garantiza que siga libre en tu ROM. Puedes consultar el [https://www.smwcentral.net/?p=memorymap&amp;amp;game=smw&amp;amp;region=ram mapa de RAM de SMW Central].&lt;br /&gt;
&lt;br /&gt;
== Reservar paletas para otros recursos ==&lt;br /&gt;
&lt;br /&gt;
Si una animación, un HUD u otro recurso necesita una paleta fija, conviene reservarla para que Dynamic Xtreme no la elija al asignar colores a los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
Para reservarla, escribe &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; en su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt;. Cada entrada ocupa 2 bytes. Por ejemplo, la paleta 9 utiliza el desplazamiento &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;: 9 × 2.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$FFFE&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_ID+$12    ; Reservar la paleta 9&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para reservar varias, escribe el mismo valor en sus entradas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Paleta !! Desplazamiento&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| A || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| B || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| C || &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| D || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| E || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| F || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La reserva impide que la asignación automática reclame esa paleta; no carga colores por sí misma. Un recurso configurado para utilizarla manualmente todavía puede cambiar sus colores, por lo que no debes asignársela también a otro recurso que necesite una paleta diferente.&lt;br /&gt;
&lt;br /&gt;
== Elegir el espacio de VRAM para sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Los sprites dinámicos necesitan una parte de VRAM donde cargar sus poses. Elige un espacio que no estés utilizando para gráficos fijos del nivel.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para permitir que utilicen SP4:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si necesitas más espacio y el nivel lo permite, puedes elegir &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; para SP3 y SP4, o &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt; para SP2, SP3 y SP4. Hay más opciones, incluidas medias páginas y configuraciones para compartir espacio con el jugador o DSX.&lt;br /&gt;
&lt;br /&gt;
Los defines disponibles están en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y en la [[es/Dynamic_Xtreme_ASM_API#Configuraciones_de_espacio_para_poses_dinámicas|tabla de configuraciones de la API]]. Configura el espacio antes de que el nivel empiece a cargar poses; cambiarlo no elimina automáticamente las poses que ya estaban en VRAM.&lt;br /&gt;
&lt;br /&gt;
== Configurar la cantidad de datos que se transfieren por frame ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; indica cuántos bytes pueden programar las cargas normales de Dynamic Xtreme durante un frame. Lo comparten las poses dinámicas, las animaciones y las demás transferencias realizadas con sus macros.&lt;br /&gt;
&lt;br /&gt;
El valor predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Este ejemplo lo aumenta a &amp;lt;code&amp;gt;$0A00&amp;lt;/code&amp;gt;, equivalente a 2560 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0A00&lt;br /&gt;
    STA.l DX_Dynamic_MaxDataPerFrame&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Subirlo permite intentar más cargas durante el mismo frame, pero no aumenta el tiempo que tiene SNES para copiarlas. Si la cantidad total es excesiva, pueden aparecer problemas visuales. Ajusta el valor según el nivel y comprueba el resultado con sus sprites y animaciones funcionando juntos.&lt;br /&gt;
&lt;br /&gt;
Las macros normales devuelven el carry desactivado si una carga no cabe en el límite. En ese caso, conserva lo que ya se muestra y vuelve a intentarlo después. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; se saltan la comprobación y también suman sus bytes al total.&lt;br /&gt;
&lt;br /&gt;
== Crear animaciones de gráficos ==&lt;br /&gt;
&lt;br /&gt;
Este código conserva el funcionamiento del ejemplo &amp;lt;code&amp;gt;Exanimation&amp;lt;/code&amp;gt;: una tabla indica dónde empieza cada imagen, un temporizador controla cuándo cambiarla y la imagen anterior se mantiene si no se acepta la transferencia.&lt;br /&gt;
&lt;br /&gt;
Declara los archivos del ejemplo en &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Aquí pon RAM libre: un byte distinto para cada variable.&lt;br /&gt;
!CurrentPoseIndex = RAM_LIBRE_ANIM_POSE&lt;br /&gt;
!AnimationTimer = RAM_LIBRE_ANIM_TIMER&lt;br /&gt;
!PaletteLoaded = RAM_LIBRE_ANIM_PALETA&lt;br /&gt;
&lt;br /&gt;
; Frames de espera antes de intentar el siguiente cambio.&lt;br /&gt;
!TimePerPose = $03&lt;br /&gt;
&lt;br /&gt;
; Bytes de cada imagen: un tile de 8x8 en 4bpp ocupa $0020.&lt;br /&gt;
!DataSend = $0200&lt;br /&gt;
&lt;br /&gt;
; Cantidad de imágenes utilizadas.&lt;br /&gt;
!NumberOfPoses = $05&lt;br /&gt;
&lt;br /&gt;
; Origen: recurso instalado. También puedes usar !AN2Buffer2.&lt;br /&gt;
!Source = !ResourceSMMArrow&lt;br /&gt;
&lt;br /&gt;
; Dirección de destino en VRAM.&lt;br /&gt;
!Destination = !BG2Line0&lt;br /&gt;
&lt;br /&gt;
; Paleta instalada y primer color de destino.&lt;br /&gt;
!Palette = &amp;quot;SMMArrowPal&amp;quot;&lt;br /&gt;
!PaletteDestination = $71&lt;br /&gt;
&lt;br /&gt;
; 0 = sin efecto global; 1 = recibe el efecto global.&lt;br /&gt;
!PaletteGlobalEffect = 0&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    STZ !CurrentPoseIndex&lt;br /&gt;
    LDA #!TimePerPose&lt;br /&gt;
    STA !AnimationTimer&lt;br /&gt;
    STZ !PaletteLoaded&lt;br /&gt;
&lt;br /&gt;
    %ForcedTransferToVRAM(#!Destination, #!Source, #((!Source&amp;gt;&amp;gt;16)&amp;amp;$FF), #!DataSend)&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteLoaded&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; Reintentar la paleta si no se aceptó durante init.&lt;br /&gt;
    LDA !PaletteLoaded&lt;br /&gt;
    BNE .Animate&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCS .PaletteReady&lt;br /&gt;
    RTL&lt;br /&gt;
.PaletteReady&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteLoaded&lt;br /&gt;
&lt;br /&gt;
.Animate&lt;br /&gt;
    LDA !AnimationTimer&lt;br /&gt;
    BEQ .NextPose&lt;br /&gt;
    DEC !AnimationTimer&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
.NextPose&lt;br /&gt;
    LDA !CurrentPoseIndex&lt;br /&gt;
    INC A&lt;br /&gt;
    CMP #!NumberOfPoses&lt;br /&gt;
    BCC .SelectPose&lt;br /&gt;
    LDA #$00&lt;br /&gt;
.SelectPose&lt;br /&gt;
    STA $05&lt;br /&gt;
    ASL&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l PosesTable,x&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC.w #!Source&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    %TransferToVRAM(#!Destination, $00, #((!Source&amp;gt;&amp;gt;16)&amp;amp;$FF), #!DataSend)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA $05&lt;br /&gt;
    STA !CurrentPoseIndex&lt;br /&gt;
    LDA #!TimePerPose&lt;br /&gt;
    STA !AnimationTimer&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
PosesTable:&lt;br /&gt;
    dw $0000&lt;br /&gt;
    dw !DataSend*$01&lt;br /&gt;
    dw !DataSend*$02&lt;br /&gt;
    dw !DataSend*$03&lt;br /&gt;
    dw !DataSend*$04&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!TimePerPose&amp;lt;/code&amp;gt;: tiempo de espera. Con &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;, el cambio se intenta cada cuatro frames: tres para descontar el temporizador y uno para realizar el cambio.&lt;br /&gt;
* &amp;lt;code&amp;gt;!DataSend&amp;lt;/code&amp;gt;: bytes de cada imagen. &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; equivale a 16 tiles de 8×8 en 4bpp.&lt;br /&gt;
* &amp;lt;code&amp;gt;!NumberOfPoses&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PosesTable&amp;lt;/code&amp;gt;: cantidad de imágenes y sus desplazamientos dentro del origen. El ejemplo utiliza las primeras cinco imágenes de &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;. Si añades más, amplía también la tabla.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Source&amp;lt;/code&amp;gt;: dirección de los gráficos. El ejemplo lee directamente &amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt;; para animar gráficos ya preparados por Lunar Magic puedes usar &amp;lt;code&amp;gt;!AN2Buffer2&amp;lt;/code&amp;gt;, como en el código original.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Destination&amp;lt;/code&amp;gt;: zona de VRAM que se actualizará. Coloca en el nivel tiles que utilicen esa zona y comprueba que otro recurso no la sobrescriba.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteDestination&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt;: paleta, primer color de destino y participación en el efecto global.&lt;br /&gt;
&lt;br /&gt;
Reemplaza los tres marcadores de RAM del principio por direcciones disponibles durante todo el nivel: cada variable necesita un byte propio. No son scratch temporales. &amp;lt;code&amp;gt;!PaletteLoaded&amp;lt;/code&amp;gt; permite reintentar una carga de paleta rechazada sin repetirla después de que haya sido aceptada.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt; se generan al instalar el DynamicInfo y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres se normalizan en PascalCase eliminando separadores; en este caso se conservan las mayúsculas de &amp;lt;code&amp;gt;SMMArrow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Todas las imágenes utilizadas deben quedar en el mismo banco del origen. La carga inicial de gráficos utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;; los siguientes cambios respetan el límite de datos por frame. Si una carga se rechaza, el código conserva la imagen anterior y vuelve a intentarla en el siguiente frame, sin avanzar el índice ni reiniciar el temporizador.&lt;br /&gt;
&lt;br /&gt;
Como en el original, el temporizador avanza cada vez que se ejecuta &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;. Si quieres detener la animación durante la pausa o cuando se congela la acción, puedes comprobar &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; antes de descontarlo.&lt;br /&gt;
&lt;br /&gt;
== Cambiar paletas durante el juego ==&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; permiten cargar colores y mantener actualizadas las copias que utilizan SMW y Dynamic Xtreme. También se encargan de preparar los efectos de paleta, por lo que no necesitas copiar buffers ni borrar indicadores a mano.&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza &amp;lt;code&amp;gt;SMMArrowPal.bin&amp;lt;/code&amp;gt;, un archivo de 15 colores (&amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes), y cambia los colores 1-F de la paleta 7. El color 0 queda sin modificar.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;, declara los gráficos como recurso general y la paleta en &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ASM del nivel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Aquí pon una RAM libre de un byte.&lt;br /&gt;
!PaletteChangePending = RAM_LIBRE_CAMBIO_PALETA&lt;br /&gt;
&lt;br /&gt;
!Palette = &amp;quot;SMMArrowPal&amp;quot;&lt;br /&gt;
!PaletteDestination = $71&lt;br /&gt;
!PaletteGlobalEffect = 1&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteChangePending&lt;br /&gt;
    ; Continuar con el primer intento de carga.&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA !PaletteChangePending&lt;br /&gt;
    BNE .TryTransfer&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.TryTransfer&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    ; Confirmar el cambio solo si la llamada fue aceptada.&lt;br /&gt;
    STZ !PaletteChangePending&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reemplaza &amp;lt;code&amp;gt;RAM_LIBRE_CAMBIO_PALETA&amp;lt;/code&amp;gt; por una dirección de RAM libre de un byte, disponible durante todo el nivel. &amp;lt;code&amp;gt;!PaletteChangePending&amp;lt;/code&amp;gt; se pone en 1 al solicitar el cambio y solo vuelve a 0 cuando la macro devuelve el carry activado. Si la llamada falla, el cambio queda pendiente y se reintenta en el siguiente frame. Una vez aceptado, no se repite la carga.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt; selecciona el recurso y &amp;lt;code&amp;gt;!PaletteDestination&amp;lt;/code&amp;gt; el primer color de destino. &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt;, utilizado como último parámetro de la macro, elige cómo se carga:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;: prepara los colores originales para que reciban el efecto global antes de mostrarse. También deja la paleta preparada si todavía no has seleccionado un efecto.&lt;br /&gt;
* &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;: carga los colores sin efecto global y excluye esa paleta del efecto. Además actualiza los buffers de SMW, necesarios para evitar problemas de colores durante la animación de victoria del goal.&lt;br /&gt;
&lt;br /&gt;
Para cargar la misma paleta sin efecto global, cambia únicamente este define; conserva la comprobación del carry:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!PaletteGlobalEffect = 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si los efectos están deshabilitados en la instalación, ambas opciones realizan una carga directa. Cuando están habilitados y utilizas &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, el sistema carga el resultado ya procesado; no se muestra primero la paleta sin efecto durante un frame.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; utiliza los defines &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt;, generados desde &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; del DynamicInfo y publicados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra. En este caso se conserva &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; tal como está escrito.&lt;br /&gt;
&lt;br /&gt;
Para solicitar de nuevo el cambio durante el juego, pon &amp;lt;code&amp;gt;!PaletteChangePending&amp;lt;/code&amp;gt; en 1 cuando se cumpla la condición que elijas. No lo hagas cada frame si la paleta no cambia. En una carga directa, el carry activado indica que se programó la transferencia; con efecto global, indica que los colores originales quedaron preparados, no que el resultado ya esté en pantalla.&lt;br /&gt;
&lt;br /&gt;
La opción de efecto se aplica a toda la paleta de 16 colores. Si cargas colores para recibir un efecto global, prepara todos sus colores visibles, como los 15 de este ejemplo; no cambies solo unos pocos esperando conservar una base que todavía no has preparado.&lt;br /&gt;
&lt;br /&gt;
Si eliges una paleta de sprites 8-F para un uso fijo, resérvala primero como se explica al comienzo del artículo. Estas macros no realizan asignación automática. Para cargar desde una dirección, un puntero o una tabla, consulta [[es/Dynamic_Xtreme_ASM_API#Cargar_colores_con_TransferPalette|Cargar colores con TransferPalette en la API]].&lt;br /&gt;
&lt;br /&gt;
== Cambiar los gráficos del jugador ==&lt;br /&gt;
&lt;br /&gt;
El ejemplo &amp;lt;code&amp;gt;Player Change&amp;lt;/code&amp;gt; alterna entre el jugador original y Geno al pulsar arriba. Conserva sus defines para elegir los gráficos y las cuatro paletas: Mario, Luigi, Mario con fuego y Luigi con fuego. También vuelve a seleccionar la paleta cuando cambia el estado del jugador.&lt;br /&gt;
&lt;br /&gt;
Necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; habilitado. Los gráficos personalizados deben utilizar la misma organización de poses que los originales; cambiar el origen no adapta un spritesheet de otro formato.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/Geno.dynamicinfo&amp;lt;/code&amp;gt;, declara:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    Geno.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    GenoPal.bin&lt;br /&gt;
    GenoPalPlayer2.bin&lt;br /&gt;
    FireGenoPal.bin&lt;br /&gt;
    FireGenoPalPlayer2.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/Geno.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Aquí pon una RAM libre de dos bytes consecutivos.&lt;br /&gt;
!Last0D82 = RAM_LIBRE_JUGADOR_2_BYTES&lt;br /&gt;
&lt;br /&gt;
; Gráficos del jugador personalizado.&lt;br /&gt;
!PlayerGFXResource = !ResourceGeno&lt;br /&gt;
&lt;br /&gt;
; Paletas: jugador 1, jugador 2 y sus variantes con fuego.&lt;br /&gt;
!PlayerGFXPalette = !PaletteGenoPal&lt;br /&gt;
!PlayerGFXPalettePlayer2 = !PaletteGenoPalPlayer2&lt;br /&gt;
!PlayerGFXFirePalette = !PaletteFireGenoPal&lt;br /&gt;
!PlayerGFXFirePalettePlayer2 = !PaletteFireGenoPalPlayer2&lt;br /&gt;
&lt;br /&gt;
; Botón de cambio: $08 = arriba.&lt;br /&gt;
!ChangeButton = $08&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA !Last0D82&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA !ButtonDown_BYETUDLR&lt;br /&gt;
    AND #!ChangeButton&lt;br /&gt;
    BNE .Change&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    CMP !Last0D82&lt;br /&gt;
    BNE .Reload&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
.Change&lt;br /&gt;
    LDA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    CMP.b #!GFX32Buffer&amp;gt;&amp;gt;16&lt;br /&gt;
    BEQ .ChooseGeno&lt;br /&gt;
    JMP .Mario&lt;br /&gt;
.ChooseGeno&lt;br /&gt;
    JMP .Geno&lt;br /&gt;
&lt;br /&gt;
.Reload&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    CMP.b #!GFX32Buffer&amp;gt;&amp;gt;16&lt;br /&gt;
    BNE .Geno&lt;br /&gt;
    JMP .Mario&lt;br /&gt;
&lt;br /&gt;
.Geno&lt;br /&gt;
    ; Obtener 0, 1, 2 o 3 según jugador y estado de fuego.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    SEC&lt;br /&gt;
    SBC #!PlayerBasePalette&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    %DivW($01, $00, #$14)&lt;br /&gt;
&lt;br /&gt;
    ; Cada dirección de GenoPals ocupa tres bytes.&lt;br /&gt;
    LDA !DivisionResult&lt;br /&gt;
    ASL&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC !DivisionResult&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    ; Conservar el origen elegido y preparar los colores 2-5.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l GenoPals,x&lt;br /&gt;
    STA $03&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$0002&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.l GenoPals+2,x&lt;br /&gt;
    STA $02&lt;br /&gt;
    STA $05&lt;br /&gt;
&lt;br /&gt;
    %TransferPaletteFromPointer($00, #$82, $0008, 0)&lt;br /&gt;
    BCS .ApplyGeno&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.ApplyGeno&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!PlayerGFXResource&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!PlayerGFXResource&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
&lt;br /&gt;
    ; La rutina del jugador carga los colores 6-F.&lt;br /&gt;
    LDA $03&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$000A&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA $05&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    JMP .ConfirmSelection&lt;br /&gt;
&lt;br /&gt;
.Mario&lt;br /&gt;
    %TransferPaletteFromAddress(!PlayerPaletteColor2To5, #$82, $0008, 0)&lt;br /&gt;
    BCS .ApplyMario&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.ApplyMario&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!GFX32Buffer&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    LDA.w #(!GFX32Buffer&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
.ConfirmSelection&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA !Last0D82&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
GenoPals:&lt;br /&gt;
    dl !PlayerGFXPalette&lt;br /&gt;
    dl !PlayerGFXPalettePlayer2&lt;br /&gt;
    dl !PlayerGFXFirePalette&lt;br /&gt;
    dl !PlayerGFXFirePalettePlayer2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!PlayerGFXResource&amp;lt;/code&amp;gt;: gráficos del personaje personalizado.&lt;br /&gt;
* Los cuatro defines &amp;lt;code&amp;gt;!PlayerGFX...Palette...&amp;lt;/code&amp;gt;: direcciones de sus paletas, en el orden de la tabla &amp;lt;code&amp;gt;GenoPals&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ChangeButton&amp;lt;/code&amp;gt;: botón que alterna entre los personajes. Utiliza los bits del control &amp;lt;code&amp;gt;BYETUDLR&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; corresponde a arriba.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Last0D82&amp;lt;/code&amp;gt;: reemplaza &amp;lt;code&amp;gt;RAM_LIBRE_JUGADOR_2_BYTES&amp;lt;/code&amp;gt; por una dirección de RAM libre con dos bytes consecutivos disponibles. Guarda la selección de paleta del juego; ninguno de esos bytes debe estar ocupado por otro código.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGeno&amp;lt;/code&amp;gt; y los defines &amp;lt;code&amp;gt;!PaletteGenoPal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteGenoPalPlayer2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteFireGenoPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteFireGenoPalPlayer2&amp;lt;/code&amp;gt; se generan desde el DynamicInfo y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres usan PascalCase eliminando espacios, guiones y guiones bajos, y conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
El código mantiene el formato de las paletas del paquete: cada archivo contiene los colores 1-F. Se omite su primer color para copiar los colores 2-5; los últimos diez comienzan en &amp;lt;code&amp;gt;+$0A&amp;lt;/code&amp;gt; y los utiliza la rutina del jugador.&lt;br /&gt;
&lt;br /&gt;
Las cargas de los colores 2-5 ahora utilizan &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, que también actualiza los buffers de SMW. El ejemplo no confirma el cambio de gráficos si esa transferencia es rechazada. Un cambio pendiente por el estado del jugador se vuelve a intentar mientras no coincida con &amp;lt;code&amp;gt;!Last0D82&amp;lt;/code&amp;gt;; si se rechaza un cambio solicitado con el botón, vuelve a pulsarlo.&lt;br /&gt;
&lt;br /&gt;
Como en el paquete original, el código distingue al jugador original por el banco de &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt;. Si lo adaptas para alternar entre varios personajes personalizados en ROM, necesitarás otra forma de recordar cuál está seleccionado.&lt;br /&gt;
&lt;br /&gt;
Este ejemplo carga la paleta del jugador sin efecto global. No basta con cambiar a &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; el parámetro de una carga de cuatro colores para añadirle un efecto: en ese caso hay que preparar todos los colores visibles de la paleta 8 y respetar su carga especial.&lt;br /&gt;
&lt;br /&gt;
== Aplicar un efecto global de paleta ==&lt;br /&gt;
&lt;br /&gt;
Los tres ejemplos de efectos conservan los ajustes del paquete: puedes elegir cada paleta por separado, incluir el color fijo y seleccionar los IDs de inicio y final. Los códigos de ciclo y transición también permiten configurar la velocidad con &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los archivos &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; siguientes conservan la cantidad y el orden de efectos de los originales. Se actualizan al formato actual usando &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; y convirtiendo los ratios de 0-31 a 0-127. Los valores &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt; continúan entre 0 y 31.&lt;br /&gt;
&lt;br /&gt;
=== Elegir las paletas afectadas ===&lt;br /&gt;
&lt;br /&gt;
En cada código, cambia &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt; a 1 para incluir la paleta correspondiente o a 0 para excluirla. &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; controla el color fijo y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt; permite incluir también el color 0,0.&lt;br /&gt;
&lt;br /&gt;
Las máscaras &amp;lt;code&amp;gt;!EnableBG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableSP&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColors&amp;lt;/code&amp;gt; se calculan a partir de esos ajustes. No necesitas modificarlas a mano. En la API actual, el bit bajo corresponde a la primera paleta de cada grupo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor del bit !! Paleta de fondo !! Paleta de sprites&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || 0 || 8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || 1 || 9&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || 2 || A&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || 3 || B&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || 4 || C&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || 5 || D&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || 6 || E&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; || 7 || F&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
El color fijo y el color 0,0 utilizan &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt;: bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; y bit &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, respectivamente. Esto sustituye la variable antigua &amp;lt;code&amp;gt;DX_PPU_FixedColor_Enable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
En sprites con asignación dinámica, configura también el bit E de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;. Si cargas paletas mediante &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, su último parámetro determina si esas paletas participan en el efecto global. Evita que otro código vuelva a escribir máscaras distintas sin tener en cuenta esa configuración.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto fijo ===&lt;br /&gt;
&lt;br /&gt;
El código &amp;lt;code&amp;gt;SimpleGlobalPaletteEffect&amp;lt;/code&amp;gt; aplica el efecto que indiques en &amp;lt;code&amp;gt;!PaletteEffetID&amp;lt;/code&amp;gt;. Esta es su configuración original: todas las paletas y el color fijo habilitados, con el último efecto de &amp;lt;code&amp;gt;DecreaseSaturation&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Guarda esta versión actualizada de &amp;lt;code&amp;gt;DecreaseSaturation.paleffect&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DynamicXtreme/DecreaseSaturation.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 4, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 8, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 12, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 16, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 20, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 25, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 29, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 33, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 37, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 41, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 45, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 49, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 53, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 57, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 61, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 66, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 70, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 74, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 78, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 82, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 86, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 90, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 94, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 98, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 102, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 107, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 111, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 115, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 119, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 123, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 11}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Se conservan sus 32 entradas, incluida la última repetida. &amp;lt;code&amp;gt;EffectType = 11&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;Channel2 = 0&amp;lt;/code&amp;gt; indica que se reduce la saturación y &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; controla cuánto. El último efecto utiliza 127, que aplica el cambio completo.&lt;br /&gt;
&lt;br /&gt;
El ASM actualizado es:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/DecreaseSaturation.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 1&lt;br /&gt;
!P2 = 1&lt;br /&gt;
!P3 = 1&lt;br /&gt;
!P4 = 1&lt;br /&gt;
!P5 = 1&lt;br /&gt;
!P6 = 1&lt;br /&gt;
!P7 = 1&lt;br /&gt;
&lt;br /&gt;
!P8 = 1&lt;br /&gt;
!P9 = 1&lt;br /&gt;
!PA = 1&lt;br /&gt;
!PB = 1&lt;br /&gt;
!PC = 1&lt;br /&gt;
!PD = 1&lt;br /&gt;
!PE = 1&lt;br /&gt;
!PF = 1&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Efecto que se aplica al entrar al nivel.&lt;br /&gt;
!PaletteEffetID = !PaletteEffectIDDecreaseSaturation31&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;: paletas afectadas.&lt;br /&gt;
* &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: participación de esos colores.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteEffetID&amp;lt;/code&amp;gt;: efecto seleccionado. Puedes utilizar cualquier ID generado desde tu archivo de efectos, no solo el último de este ejemplo.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation31&amp;lt;/code&amp;gt; se generan desde el &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando espacios, guiones y guiones bajos, y conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
La selección se realiza en &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;; no hace falta repetirla cada frame. Para quitar el efecto, escribe 0 en el ID global y deja las paletas habilitadas para que el sistema restaure sus colores originales:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hacer que el efecto se repita en un ciclo ===&lt;br /&gt;
&lt;br /&gt;
El código &amp;lt;code&amp;gt;GlobalPaletteEffect Cycle&amp;lt;/code&amp;gt; recorre una secuencia de efectos y vuelve al primero. Conserva sus opciones de velocidad, primer y último ID y selección de paletas. Como en el original, la configuración inicial incluye solo la paleta 0 y el color fijo.&lt;br /&gt;
&lt;br /&gt;
Guarda esta versión de &amp;lt;code&amp;gt;Hue.paleffect&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DynamicXtreme/Hue.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 1, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 2, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 3, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 4, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 5, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 6, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 7, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 8, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 9, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 10, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 11, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 12, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 13, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 14, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 15, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 16, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 17, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 18, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 19, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 20, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 21, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 22, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 23, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 24, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 25, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 26, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 27, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 28, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 29, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 30, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 31, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 31, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Se conservan los 32 efectos del archivo original, con el tono 31 repetido al final. &amp;lt;code&amp;gt;EffectType = 9&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio1 = 127&amp;lt;/code&amp;gt; aplica por completo el tono seleccionado.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Hue.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 0&lt;br /&gt;
!P2 = 0&lt;br /&gt;
!P3 = 0&lt;br /&gt;
!P4 = 0&lt;br /&gt;
!P5 = 0&lt;br /&gt;
!P6 = 0&lt;br /&gt;
!P7 = 0&lt;br /&gt;
&lt;br /&gt;
!P8 = 0&lt;br /&gt;
!P9 = 0&lt;br /&gt;
!PA = 0&lt;br /&gt;
!PB = 0&lt;br /&gt;
!PC = 0&lt;br /&gt;
!PD = 0&lt;br /&gt;
!PE = 0&lt;br /&gt;
!PF = 0&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Valores permitidos: $00, $01, $03, $07, $0F, $1F, $3F, $7F y $FF.&lt;br /&gt;
!Delay = $03&lt;br /&gt;
&lt;br /&gt;
!StartingPaletteEffetID = !PaletteEffectIDHue0&lt;br /&gt;
!EndPaletteEffetID = !PaletteEffectIDHue31&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #!Delay&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!EndPaletteEffetID&lt;br /&gt;
    BCS .Restart&lt;br /&gt;
    INC A&lt;br /&gt;
    BRA .Store&lt;br /&gt;
.Restart&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
.Store&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: colores afectados.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;: separación entre cambios. &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; cambia cada frame, &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; cada dos, &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; cada cuatro y &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; cada ocho. Utiliza únicamente los valores indicados en el comentario.&lt;br /&gt;
* &amp;lt;code&amp;gt;!StartingPaletteEffetID&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EndPaletteEffetID&amp;lt;/code&amp;gt;: primer y último efecto del ciclo. Deben pertenecer a una secuencia de IDs consecutivos, con el inicio menor o igual que el final.&lt;br /&gt;
&lt;br /&gt;
El ciclo muestra el último ID antes de volver al primero. Conserva el uso de &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; del original para marcar el momento de los cambios; por ello, el primer intervalo depende del valor que tenga ese contador al entrar al nivel. Si quieres detenerlo al congelarse la acción, comprueba también &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt; al comienzo de &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDHue0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDHue31&amp;lt;/code&amp;gt; se generan desde el &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores; en este caso conserva &amp;lt;code&amp;gt;Hue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Hacer una transición que se detiene al terminar ===&lt;br /&gt;
&lt;br /&gt;
El código &amp;lt;code&amp;gt;GlobalPaletteEffect Transition&amp;lt;/code&amp;gt; avanza desde el efecto inicial hasta el final y conserva ese último resultado. Mantiene la configuración original de paletas, color fijo, velocidad y rango de IDs.&lt;br /&gt;
&lt;br /&gt;
Guarda esta versión de &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DynamicXtreme/Night.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 0, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 4, &amp;quot;Ratio2&amp;quot;: 4, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 8, &amp;quot;Ratio2&amp;quot;: 8, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 12, &amp;quot;Ratio2&amp;quot;: 12, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 16, &amp;quot;Ratio2&amp;quot;: 16, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 20, &amp;quot;Ratio2&amp;quot;: 20, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 25, &amp;quot;Ratio2&amp;quot;: 25, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 29, &amp;quot;Ratio2&amp;quot;: 29, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 33, &amp;quot;Ratio2&amp;quot;: 33, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 37, &amp;quot;Ratio2&amp;quot;: 37, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 41, &amp;quot;Ratio2&amp;quot;: 41, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 45, &amp;quot;Ratio2&amp;quot;: 45, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 49, &amp;quot;Ratio2&amp;quot;: 49, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 53, &amp;quot;Ratio2&amp;quot;: 53, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 57, &amp;quot;Ratio2&amp;quot;: 57, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 61, &amp;quot;Ratio2&amp;quot;: 61, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 66, &amp;quot;Ratio2&amp;quot;: 66, &amp;quot;EffectType&amp;quot;: 2}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Estos son los mismos 17 pasos del original. &amp;lt;code&amp;gt;EffectType = 2&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixRG&amp;lt;/code&amp;gt;: reduce el rojo y el verde sin modificar el azul. Los ratios antiguos 0-16 pasan aproximadamente a 0-66; no se amplían hasta 127 porque eso haría el cambio más intenso que en el archivo original.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Night.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 1&lt;br /&gt;
!P2 = 1&lt;br /&gt;
!P3 = 1&lt;br /&gt;
!P4 = 1&lt;br /&gt;
!P5 = 1&lt;br /&gt;
!P6 = 1&lt;br /&gt;
!P7 = 1&lt;br /&gt;
&lt;br /&gt;
!P8 = 1&lt;br /&gt;
!P9 = 1&lt;br /&gt;
!PA = 1&lt;br /&gt;
!PB = 1&lt;br /&gt;
!PC = 1&lt;br /&gt;
!PD = 1&lt;br /&gt;
!PE = 1&lt;br /&gt;
!PF = 1&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Valores permitidos: $00, $01, $03, $07, $0F, $1F, $3F, $7F y $FF.&lt;br /&gt;
!Delay = $03&lt;br /&gt;
&lt;br /&gt;
!StartingPaletteEffetID = !PaletteEffectIDNight0&lt;br /&gt;
!EndPaletteEffetID = !PaletteEffectIDNight16&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #!Delay&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!EndPaletteEffetID&lt;br /&gt;
    BCS .Finished&lt;br /&gt;
    INC A&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
.Finished&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: colores afectados.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;: tiempo entre cambios, con los mismos valores permitidos en el ejemplo de ciclo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!StartingPaletteEffetID&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EndPaletteEffetID&amp;lt;/code&amp;gt;: primer y último efecto. Deben ser IDs consecutivos en orden ascendente.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDNight16&amp;lt;/code&amp;gt; se generan desde &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres usan PascalCase eliminando separadores; aquí se conserva &amp;lt;code&amp;gt;Night&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para actualizar otros archivos antiguos, convierte cada ratio con &amp;lt;code&amp;gt;ratio antiguo × 127 ÷ 31&amp;lt;/code&amp;gt;, redondeando al entero más cercano, y utiliza el &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; correspondiente. No multipliques los valores &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt;: siguen utilizando 0-31.&lt;br /&gt;
&lt;br /&gt;
Este ejemplo cambia entre efectos de mezcla, igual que el original. Para una transición hacia otra paleta completa, utiliza &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt;, explicados en [[es/Dynamic_Xtreme_files_and_formats#Transiciones_de_paleta|Archivos y formatos]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21361</id>
		<title>es/Dynamic Xtreme UberASM guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21361"/>
		<updated>2026-10-24T22:51:49Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_UberASM_guide}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo utilizar Dynamic Xtreme desde UberASM para configurar los recursos de un nivel y crear cambios de gráficos y colores durante el juego. Se incluyen ejemplos para reservar paletas, elegir el espacio disponible para sprites dinámicos, crear animaciones y modificar los gráficos del jugador.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Tener UberASMTool instalado y configurado para insertar códigos en tu ROM.&lt;br /&gt;
* Tener Dynamic Xtreme instalado con las funciones necesarias para el ejemplo que quieras utilizar. Consulta la [[es/Dynamic_Xtreme_Quick_Start|guía de inicio rápido]] para su instalación.&lt;br /&gt;
&lt;br /&gt;
Para consultar los parámetros de una llamada o el uso de una variable, utiliza la [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]].&lt;br /&gt;
&lt;br /&gt;
== Preparar los ejemplos ==&lt;br /&gt;
&lt;br /&gt;
Cada ejemplo es independiente. Guarda el código de nivel en la carpeta correspondiente de UberASMTool y añádelo a su lista. Si reúnes varios ejemplos en un archivo, combina sus bloques &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; para no repetir las mismas etiquetas.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt; prepara datos durante la carga del nivel. Se utiliza aquí para reservar paletas antes de que las reclamen los sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; prepara las opciones al entrar al nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; ejecuta el código durante el juego, una vez por frame.&lt;br /&gt;
&lt;br /&gt;
Los defines y macros de Dynamic Xtreme deben estar disponibles en UberASMTool mediante la integración realizada durante la instalación. Si utilizas gráficos, paletas o efectos adicionales, decláralos en el ASM mediante los includes correspondientes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MyResources.dynamicinfo&amp;quot;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/MyEffect.paleffect&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las rutas son relativas al ASM. Incluye únicamente los archivos que utiliza tu ejemplo. También puedes usar las carpetas tradicionales de Dynamic Xtreme, como se explica en [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
&lt;br /&gt;
Después de añadir o modificar estos recursos, instala primero Dynamic Xtreme y después UberASMTool. Si solo cambias la lógica del ASM, basta con volver a ejecutar UberASMTool.&lt;br /&gt;
&lt;br /&gt;
== Reservar paletas para otros recursos ==&lt;br /&gt;
&lt;br /&gt;
Si una animación, un HUD u otro recurso necesita una paleta fija, conviene reservarla para que Dynamic Xtreme no la elija al asignar colores a los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
Para reservarla, escribe &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; en su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt;. Cada entrada ocupa 2 bytes. Por ejemplo, la paleta 9 utiliza el desplazamiento &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;: 9 × 2.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$FFFE&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_ID+$12    ; Reservar la paleta 9&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para reservar varias, escribe el mismo valor en sus entradas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Paleta !! Desplazamiento&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| A || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| B || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| C || &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| D || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| E || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| F || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La reserva impide que la asignación automática reclame esa paleta; no carga colores por sí misma. Un recurso configurado para utilizarla manualmente todavía puede cambiar sus colores, por lo que no debes asignársela también a otro recurso que necesite una paleta diferente.&lt;br /&gt;
&lt;br /&gt;
== Elegir el espacio de VRAM para sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Los sprites dinámicos necesitan una parte de VRAM donde cargar sus poses. Elige un espacio que no estés utilizando para gráficos fijos del nivel.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para permitir que utilicen SP4:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si necesitas más espacio y el nivel lo permite, puedes elegir &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; para SP3 y SP4, o &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt; para SP2, SP3 y SP4. Hay más opciones, incluidas medias páginas y configuraciones para compartir espacio con el jugador o DSX.&lt;br /&gt;
&lt;br /&gt;
Los defines disponibles están en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y en la [[es/Dynamic_Xtreme_ASM_API#Configuraciones_de_espacio_para_poses_dinámicas|tabla de configuraciones de la API]]. Configura el espacio antes de que el nivel empiece a cargar poses; cambiarlo no elimina automáticamente las poses que ya estaban en VRAM.&lt;br /&gt;
&lt;br /&gt;
== Configurar la cantidad de datos que se transfieren por frame ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; indica cuántos bytes pueden programar las cargas normales de Dynamic Xtreme durante un frame. Lo comparten las poses dinámicas, las animaciones y las demás transferencias realizadas con sus macros.&lt;br /&gt;
&lt;br /&gt;
El valor predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Este ejemplo lo aumenta a &amp;lt;code&amp;gt;$0A00&amp;lt;/code&amp;gt;, equivalente a 2560 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0A00&lt;br /&gt;
    STA.l DX_Dynamic_MaxDataPerFrame&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Subirlo permite intentar más cargas durante el mismo frame, pero no aumenta el tiempo que tiene SNES para copiarlas. Si la cantidad total es excesiva, pueden aparecer problemas visuales. Ajusta el valor según el nivel y comprueba el resultado con sus sprites y animaciones funcionando juntos.&lt;br /&gt;
&lt;br /&gt;
Las macros normales devuelven el carry desactivado si una carga no cabe en el límite. En ese caso, conserva lo que ya se muestra y vuelve a intentarlo después. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; se saltan la comprobación y también suman sus bytes al total.&lt;br /&gt;
&lt;br /&gt;
== Crear animaciones de gráficos ==&lt;br /&gt;
&lt;br /&gt;
Este código conserva el funcionamiento del ejemplo &amp;lt;code&amp;gt;Exanimation&amp;lt;/code&amp;gt;: una tabla indica dónde empieza cada imagen, un temporizador controla cuándo cambiarla y la imagen anterior se mantiene si no se acepta la transferencia.&lt;br /&gt;
&lt;br /&gt;
Declara los archivos del ejemplo en &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; RAM para el estado de la animación: comprobar que esté disponible.&lt;br /&gt;
!CurrentPoseIndex = $58&lt;br /&gt;
!AnimationTimer = $5C&lt;br /&gt;
!PaletteLoaded = $5D&lt;br /&gt;
&lt;br /&gt;
; Frames de espera antes de intentar el siguiente cambio.&lt;br /&gt;
!TimePerPose = $03&lt;br /&gt;
&lt;br /&gt;
; Bytes de cada imagen: un tile de 8x8 en 4bpp ocupa $0020.&lt;br /&gt;
!DataSend = $0200&lt;br /&gt;
&lt;br /&gt;
; Cantidad de imágenes utilizadas.&lt;br /&gt;
!NumberOfPoses = $05&lt;br /&gt;
&lt;br /&gt;
; Origen: recurso instalado. También puedes usar !AN2Buffer2.&lt;br /&gt;
!Source = !ResourceSMMArrow&lt;br /&gt;
&lt;br /&gt;
; Dirección de destino en VRAM.&lt;br /&gt;
!Destination = !BG2Line0&lt;br /&gt;
&lt;br /&gt;
; Paleta instalada y primer color de destino.&lt;br /&gt;
!Palette = &amp;quot;SMMArrowPal&amp;quot;&lt;br /&gt;
!PaletteDestination = $71&lt;br /&gt;
&lt;br /&gt;
; 0 = sin efecto global; 1 = recibe el efecto global.&lt;br /&gt;
!PaletteGlobalEffect = 0&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    STZ !CurrentPoseIndex&lt;br /&gt;
    LDA #!TimePerPose&lt;br /&gt;
    STA !AnimationTimer&lt;br /&gt;
    STZ !PaletteLoaded&lt;br /&gt;
&lt;br /&gt;
    %ForcedTransferToVRAM(#!Destination, #!Source, #((!Source&amp;gt;&amp;gt;16)&amp;amp;$FF), #!DataSend)&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteLoaded&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; Reintentar la paleta si no se aceptó durante init.&lt;br /&gt;
    LDA !PaletteLoaded&lt;br /&gt;
    BNE .Animate&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCS .PaletteReady&lt;br /&gt;
    RTL&lt;br /&gt;
.PaletteReady&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteLoaded&lt;br /&gt;
&lt;br /&gt;
.Animate&lt;br /&gt;
    LDA !AnimationTimer&lt;br /&gt;
    BEQ .NextPose&lt;br /&gt;
    DEC !AnimationTimer&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
.NextPose&lt;br /&gt;
    LDA !CurrentPoseIndex&lt;br /&gt;
    INC A&lt;br /&gt;
    CMP #!NumberOfPoses&lt;br /&gt;
    BCC .SelectPose&lt;br /&gt;
    LDA #$00&lt;br /&gt;
.SelectPose&lt;br /&gt;
    STA $05&lt;br /&gt;
    ASL&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l PosesTable,x&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC.w #!Source&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    %TransferToVRAM(#!Destination, $00, #((!Source&amp;gt;&amp;gt;16)&amp;amp;$FF), #!DataSend)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA $05&lt;br /&gt;
    STA !CurrentPoseIndex&lt;br /&gt;
    LDA #!TimePerPose&lt;br /&gt;
    STA !AnimationTimer&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
PosesTable:&lt;br /&gt;
    dw $0000&lt;br /&gt;
    dw !DataSend*$01&lt;br /&gt;
    dw !DataSend*$02&lt;br /&gt;
    dw !DataSend*$03&lt;br /&gt;
    dw !DataSend*$04&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!TimePerPose&amp;lt;/code&amp;gt;: tiempo de espera. Con &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;, el cambio se intenta cada cuatro frames: tres para descontar el temporizador y uno para realizar el cambio.&lt;br /&gt;
* &amp;lt;code&amp;gt;!DataSend&amp;lt;/code&amp;gt;: bytes de cada imagen. &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; equivale a 16 tiles de 8×8 en 4bpp.&lt;br /&gt;
* &amp;lt;code&amp;gt;!NumberOfPoses&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PosesTable&amp;lt;/code&amp;gt;: cantidad de imágenes y sus desplazamientos dentro del origen. El ejemplo utiliza las primeras cinco imágenes de &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;. Si añades más, amplía también la tabla.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Source&amp;lt;/code&amp;gt;: dirección de los gráficos. El ejemplo lee directamente &amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt;; para animar gráficos ya preparados por Lunar Magic puedes usar &amp;lt;code&amp;gt;!AN2Buffer2&amp;lt;/code&amp;gt;, como en el código original.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Destination&amp;lt;/code&amp;gt;: zona de VRAM que se actualizará. Coloca en el nivel tiles que utilicen esa zona y comprueba que otro recurso no la sobrescriba.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteDestination&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt;: paleta, primer color de destino y participación en el efecto global.&lt;br /&gt;
&lt;br /&gt;
Las direcciones de RAM del principio deben estar disponibles durante todo el nivel. No son scratch temporales: cambia esos defines si otro código ya las utiliza. &amp;lt;code&amp;gt;!PaletteLoaded&amp;lt;/code&amp;gt; permite reintentar una carga de paleta rechazada sin repetirla después de que haya sido aceptada.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt; se generan al instalar el DynamicInfo y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres se normalizan en PascalCase eliminando separadores; en este caso se conservan las mayúsculas de &amp;lt;code&amp;gt;SMMArrow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Todas las imágenes utilizadas deben quedar en el mismo banco del origen. La carga inicial de gráficos utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;; los siguientes cambios respetan el límite de datos por frame. Si una carga se rechaza, el código conserva la imagen anterior y vuelve a intentarla en el siguiente frame, sin avanzar el índice ni reiniciar el temporizador.&lt;br /&gt;
&lt;br /&gt;
Como en el original, el temporizador avanza cada vez que se ejecuta &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;. Si quieres detener la animación durante la pausa o cuando se congela la acción, puedes comprobar &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; antes de descontarlo.&lt;br /&gt;
&lt;br /&gt;
== Cambiar paletas durante el juego ==&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; permiten cargar colores y mantener actualizadas las copias que utilizan SMW y Dynamic Xtreme. También se encargan de preparar los efectos de paleta, por lo que no necesitas copiar buffers ni borrar indicadores a mano.&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza &amp;lt;code&amp;gt;SMMArrowPal.bin&amp;lt;/code&amp;gt;, un archivo de 15 colores (&amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes), y cambia los colores 1-F de la paleta 7. El color 0 queda sin modificar.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;, declara los gráficos como recurso general y la paleta en &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ASM del nivel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Un byte de RAM: comprobar que esté disponible.&lt;br /&gt;
!PaletteChangePending = $5E&lt;br /&gt;
&lt;br /&gt;
!Palette = &amp;quot;SMMArrowPal&amp;quot;&lt;br /&gt;
!PaletteDestination = $71&lt;br /&gt;
!PaletteGlobalEffect = 1&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteChangePending&lt;br /&gt;
    ; Continuar con el primer intento de carga.&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA !PaletteChangePending&lt;br /&gt;
    BNE .TryTransfer&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.TryTransfer&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    ; Confirmar el cambio solo si la llamada fue aceptada.&lt;br /&gt;
    STZ !PaletteChangePending&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteChangePending&amp;lt;/code&amp;gt; debe utilizar un byte de RAM disponible durante todo el nivel. Se pone en 1 al solicitar el cambio y solo vuelve a 0 cuando la macro devuelve el carry activado. Si la llamada falla, el cambio queda pendiente y se reintenta en el siguiente frame. Una vez aceptado, no se repite la carga.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt; selecciona el recurso y &amp;lt;code&amp;gt;!PaletteDestination&amp;lt;/code&amp;gt; el primer color de destino. &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt;, utilizado como último parámetro de la macro, elige cómo se carga:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;: prepara los colores originales para que reciban el efecto global antes de mostrarse. También deja la paleta preparada si todavía no has seleccionado un efecto.&lt;br /&gt;
* &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;: carga los colores sin efecto global y excluye esa paleta del efecto. Además actualiza los buffers de SMW, necesarios para evitar problemas de colores durante la animación de victoria del goal.&lt;br /&gt;
&lt;br /&gt;
Para cargar la misma paleta sin efecto global, cambia únicamente este define; conserva la comprobación del carry:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!PaletteGlobalEffect = 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si los efectos están deshabilitados en la instalación, ambas opciones realizan una carga directa. Cuando están habilitados y utilizas &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, el sistema carga el resultado ya procesado; no se muestra primero la paleta sin efecto durante un frame.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; utiliza los defines &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt;, generados desde &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; del DynamicInfo y publicados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra. En este caso se conserva &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; tal como está escrito.&lt;br /&gt;
&lt;br /&gt;
Para solicitar de nuevo el cambio durante el juego, pon &amp;lt;code&amp;gt;!PaletteChangePending&amp;lt;/code&amp;gt; en 1 cuando se cumpla la condición que elijas. No lo hagas cada frame si la paleta no cambia. En una carga directa, el carry activado indica que se programó la transferencia; con efecto global, indica que los colores originales quedaron preparados, no que el resultado ya esté en pantalla.&lt;br /&gt;
&lt;br /&gt;
La opción de efecto se aplica a toda la paleta de 16 colores. Si cargas colores para recibir un efecto global, prepara todos sus colores visibles, como los 15 de este ejemplo; no cambies solo unos pocos esperando conservar una base que todavía no has preparado.&lt;br /&gt;
&lt;br /&gt;
Si eliges una paleta de sprites 8-F para un uso fijo, resérvala primero como se explica al comienzo del artículo. Estas macros no realizan asignación automática. Para cargar desde una dirección, un puntero o una tabla, consulta [[es/Dynamic_Xtreme_ASM_API#Cargar_colores_con_TransferPalette|Cargar colores con TransferPalette en la API]].&lt;br /&gt;
&lt;br /&gt;
== Cambiar los gráficos del jugador ==&lt;br /&gt;
&lt;br /&gt;
El ejemplo &amp;lt;code&amp;gt;Player Change&amp;lt;/code&amp;gt; alterna entre el jugador original y Geno al pulsar arriba. Conserva sus defines para elegir los gráficos y las cuatro paletas: Mario, Luigi, Mario con fuego y Luigi con fuego. También vuelve a seleccionar la paleta cuando cambia el estado del jugador.&lt;br /&gt;
&lt;br /&gt;
Necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; habilitado. Los gráficos personalizados deben utilizar la misma organización de poses que los originales; cambiar el origen no adapta un spritesheet de otro formato.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/Geno.dynamicinfo&amp;lt;/code&amp;gt;, declara:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    Geno.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    GenoPal.bin&lt;br /&gt;
    GenoPalPlayer2.bin&lt;br /&gt;
    FireGenoPal.bin&lt;br /&gt;
    FireGenoPalPlayer2.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/Geno.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Dos bytes de RAM: comprobar que estén disponibles.&lt;br /&gt;
!Last0D82 = $18C7|!addr&lt;br /&gt;
&lt;br /&gt;
; Gráficos del jugador personalizado.&lt;br /&gt;
!PlayerGFXResource = !ResourceGeno&lt;br /&gt;
&lt;br /&gt;
; Paletas: jugador 1, jugador 2 y sus variantes con fuego.&lt;br /&gt;
!PlayerGFXPalette = !PaletteGenoPal&lt;br /&gt;
!PlayerGFXPalettePlayer2 = !PaletteGenoPalPlayer2&lt;br /&gt;
!PlayerGFXFirePalette = !PaletteFireGenoPal&lt;br /&gt;
!PlayerGFXFirePalettePlayer2 = !PaletteFireGenoPalPlayer2&lt;br /&gt;
&lt;br /&gt;
; Botón de cambio: $08 = arriba.&lt;br /&gt;
!ChangeButton = $08&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA !Last0D82&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA !ButtonDown_BYETUDLR&lt;br /&gt;
    AND #!ChangeButton&lt;br /&gt;
    BNE .Change&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    CMP !Last0D82&lt;br /&gt;
    BNE .Reload&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
.Change&lt;br /&gt;
    LDA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    CMP.b #!GFX32Buffer&amp;gt;&amp;gt;16&lt;br /&gt;
    BEQ .ChooseGeno&lt;br /&gt;
    JMP .Mario&lt;br /&gt;
.ChooseGeno&lt;br /&gt;
    JMP .Geno&lt;br /&gt;
&lt;br /&gt;
.Reload&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    CMP.b #!GFX32Buffer&amp;gt;&amp;gt;16&lt;br /&gt;
    BNE .Geno&lt;br /&gt;
    JMP .Mario&lt;br /&gt;
&lt;br /&gt;
.Geno&lt;br /&gt;
    ; Obtener 0, 1, 2 o 3 según jugador y estado de fuego.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    SEC&lt;br /&gt;
    SBC #!PlayerBasePalette&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    %DivW($01, $00, #$14)&lt;br /&gt;
&lt;br /&gt;
    ; Cada dirección de GenoPals ocupa tres bytes.&lt;br /&gt;
    LDA !DivisionResult&lt;br /&gt;
    ASL&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC !DivisionResult&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    ; Conservar el origen elegido y preparar los colores 2-5.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l GenoPals,x&lt;br /&gt;
    STA $03&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$0002&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.l GenoPals+2,x&lt;br /&gt;
    STA $02&lt;br /&gt;
    STA $05&lt;br /&gt;
&lt;br /&gt;
    %TransferPaletteFromPointer($00, #$82, $0008, 0)&lt;br /&gt;
    BCS .ApplyGeno&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.ApplyGeno&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!PlayerGFXResource&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!PlayerGFXResource&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
&lt;br /&gt;
    ; La rutina del jugador carga los colores 6-F.&lt;br /&gt;
    LDA $03&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$000A&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA $05&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    JMP .ConfirmSelection&lt;br /&gt;
&lt;br /&gt;
.Mario&lt;br /&gt;
    %TransferPaletteFromAddress(!PlayerPaletteColor2To5, #$82, $0008, 0)&lt;br /&gt;
    BCS .ApplyMario&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.ApplyMario&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!GFX32Buffer&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    LDA.w #(!GFX32Buffer&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
.ConfirmSelection&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA !Last0D82&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
GenoPals:&lt;br /&gt;
    dl !PlayerGFXPalette&lt;br /&gt;
    dl !PlayerGFXPalettePlayer2&lt;br /&gt;
    dl !PlayerGFXFirePalette&lt;br /&gt;
    dl !PlayerGFXFirePalettePlayer2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!PlayerGFXResource&amp;lt;/code&amp;gt;: gráficos del personaje personalizado.&lt;br /&gt;
* Los cuatro defines &amp;lt;code&amp;gt;!PlayerGFX...Palette...&amp;lt;/code&amp;gt;: direcciones de sus paletas, en el orden de la tabla &amp;lt;code&amp;gt;GenoPals&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ChangeButton&amp;lt;/code&amp;gt;: botón que alterna entre los personajes. Utiliza los bits del control &amp;lt;code&amp;gt;BYETUDLR&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; corresponde a arriba.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Last0D82&amp;lt;/code&amp;gt;: dos bytes de RAM para recordar la selección de paleta del juego. Asegúrate de que ningún otro código los utilice.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGeno&amp;lt;/code&amp;gt; y los defines &amp;lt;code&amp;gt;!PaletteGenoPal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteGenoPalPlayer2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteFireGenoPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteFireGenoPalPlayer2&amp;lt;/code&amp;gt; se generan desde el DynamicInfo y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres usan PascalCase eliminando espacios, guiones y guiones bajos, y conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
El código mantiene el formato de las paletas del paquete: cada archivo contiene los colores 1-F. Se omite su primer color para copiar los colores 2-5; los últimos diez comienzan en &amp;lt;code&amp;gt;+$0A&amp;lt;/code&amp;gt; y los utiliza la rutina del jugador.&lt;br /&gt;
&lt;br /&gt;
Las cargas de los colores 2-5 ahora utilizan &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, que también actualiza los buffers de SMW. El ejemplo no confirma el cambio de gráficos si esa transferencia es rechazada. Un cambio pendiente por el estado del jugador se vuelve a intentar mientras no coincida con &amp;lt;code&amp;gt;!Last0D82&amp;lt;/code&amp;gt;; si se rechaza un cambio solicitado con el botón, vuelve a pulsarlo.&lt;br /&gt;
&lt;br /&gt;
Como en el paquete original, el código distingue al jugador original por el banco de &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt;. Si lo adaptas para alternar entre varios personajes personalizados en ROM, necesitarás otra forma de recordar cuál está seleccionado.&lt;br /&gt;
&lt;br /&gt;
Este ejemplo carga la paleta del jugador sin efecto global. No basta con cambiar a &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; el parámetro de una carga de cuatro colores para añadirle un efecto: en ese caso hay que preparar todos los colores visibles de la paleta 8 y respetar su carga especial.&lt;br /&gt;
&lt;br /&gt;
== Aplicar un efecto global de paleta ==&lt;br /&gt;
&lt;br /&gt;
Los tres ejemplos de efectos conservan los ajustes del paquete: puedes elegir cada paleta por separado, incluir el color fijo y seleccionar los IDs de inicio y final. Los códigos de ciclo y transición también permiten configurar la velocidad con &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los archivos &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; siguientes conservan la cantidad y el orden de efectos de los originales. Se actualizan al formato actual usando &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; y convirtiendo los ratios de 0-31 a 0-127. Los valores &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt; continúan entre 0 y 31.&lt;br /&gt;
&lt;br /&gt;
=== Elegir las paletas afectadas ===&lt;br /&gt;
&lt;br /&gt;
En cada código, cambia &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt; a 1 para incluir la paleta correspondiente o a 0 para excluirla. &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; controla el color fijo y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt; permite incluir también el color 0,0.&lt;br /&gt;
&lt;br /&gt;
Las máscaras &amp;lt;code&amp;gt;!EnableBG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableSP&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColors&amp;lt;/code&amp;gt; se calculan a partir de esos ajustes. No necesitas modificarlas a mano. En la API actual, el bit bajo corresponde a la primera paleta de cada grupo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor del bit !! Paleta de fondo !! Paleta de sprites&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || 0 || 8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || 1 || 9&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || 2 || A&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || 3 || B&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || 4 || C&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || 5 || D&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || 6 || E&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; || 7 || F&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
El color fijo y el color 0,0 utilizan &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt;: bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; y bit &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, respectivamente. Esto sustituye la variable antigua &amp;lt;code&amp;gt;DX_PPU_FixedColor_Enable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
En sprites con asignación dinámica, configura también el bit E de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;. Si cargas paletas mediante &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, su último parámetro determina si esas paletas participan en el efecto global. Evita que otro código vuelva a escribir máscaras distintas sin tener en cuenta esa configuración.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto fijo ===&lt;br /&gt;
&lt;br /&gt;
El código &amp;lt;code&amp;gt;SimpleGlobalPaletteEffect&amp;lt;/code&amp;gt; aplica el efecto que indiques en &amp;lt;code&amp;gt;!PaletteEffetID&amp;lt;/code&amp;gt;. Esta es su configuración original: todas las paletas y el color fijo habilitados, con el último efecto de &amp;lt;code&amp;gt;DecreaseSaturation&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Guarda esta versión actualizada de &amp;lt;code&amp;gt;DecreaseSaturation.paleffect&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DynamicXtreme/DecreaseSaturation.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 4, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 8, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 12, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 16, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 20, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 25, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 29, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 33, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 37, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 41, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 45, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 49, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 53, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 57, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 61, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 66, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 70, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 74, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 78, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 82, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 86, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 90, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 94, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 98, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 102, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 107, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 111, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 115, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 119, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 123, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 11}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Se conservan sus 32 entradas, incluida la última repetida. &amp;lt;code&amp;gt;EffectType = 11&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;Channel2 = 0&amp;lt;/code&amp;gt; indica que se reduce la saturación y &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; controla cuánto. El último efecto utiliza 127, que aplica el cambio completo.&lt;br /&gt;
&lt;br /&gt;
El ASM actualizado es:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/DecreaseSaturation.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 1&lt;br /&gt;
!P2 = 1&lt;br /&gt;
!P3 = 1&lt;br /&gt;
!P4 = 1&lt;br /&gt;
!P5 = 1&lt;br /&gt;
!P6 = 1&lt;br /&gt;
!P7 = 1&lt;br /&gt;
&lt;br /&gt;
!P8 = 1&lt;br /&gt;
!P9 = 1&lt;br /&gt;
!PA = 1&lt;br /&gt;
!PB = 1&lt;br /&gt;
!PC = 1&lt;br /&gt;
!PD = 1&lt;br /&gt;
!PE = 1&lt;br /&gt;
!PF = 1&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Efecto que se aplica al entrar al nivel.&lt;br /&gt;
!PaletteEffetID = !PaletteEffectIDDecreaseSaturation31&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;: paletas afectadas.&lt;br /&gt;
* &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: participación de esos colores.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteEffetID&amp;lt;/code&amp;gt;: efecto seleccionado. Puedes utilizar cualquier ID generado desde tu archivo de efectos, no solo el último de este ejemplo.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation31&amp;lt;/code&amp;gt; se generan desde el &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando espacios, guiones y guiones bajos, y conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
La selección se realiza en &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;; no hace falta repetirla cada frame. Para quitar el efecto, escribe 0 en el ID global y deja las paletas habilitadas para que el sistema restaure sus colores originales:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hacer que el efecto se repita en un ciclo ===&lt;br /&gt;
&lt;br /&gt;
El código &amp;lt;code&amp;gt;GlobalPaletteEffect Cycle&amp;lt;/code&amp;gt; recorre una secuencia de efectos y vuelve al primero. Conserva sus opciones de velocidad, primer y último ID y selección de paletas. Como en el original, la configuración inicial incluye solo la paleta 0 y el color fijo.&lt;br /&gt;
&lt;br /&gt;
Guarda esta versión de &amp;lt;code&amp;gt;Hue.paleffect&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DynamicXtreme/Hue.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 1, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 2, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 3, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 4, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 5, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 6, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 7, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 8, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 9, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 10, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 11, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 12, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 13, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 14, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 15, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 16, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 17, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 18, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 19, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 20, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 21, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 22, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 23, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 24, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 25, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 26, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 27, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 28, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 29, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 30, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 31, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 31, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Se conservan los 32 efectos del archivo original, con el tono 31 repetido al final. &amp;lt;code&amp;gt;EffectType = 9&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio1 = 127&amp;lt;/code&amp;gt; aplica por completo el tono seleccionado.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Hue.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 0&lt;br /&gt;
!P2 = 0&lt;br /&gt;
!P3 = 0&lt;br /&gt;
!P4 = 0&lt;br /&gt;
!P5 = 0&lt;br /&gt;
!P6 = 0&lt;br /&gt;
!P7 = 0&lt;br /&gt;
&lt;br /&gt;
!P8 = 0&lt;br /&gt;
!P9 = 0&lt;br /&gt;
!PA = 0&lt;br /&gt;
!PB = 0&lt;br /&gt;
!PC = 0&lt;br /&gt;
!PD = 0&lt;br /&gt;
!PE = 0&lt;br /&gt;
!PF = 0&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Valores permitidos: $00, $01, $03, $07, $0F, $1F, $3F, $7F y $FF.&lt;br /&gt;
!Delay = $03&lt;br /&gt;
&lt;br /&gt;
!StartingPaletteEffetID = !PaletteEffectIDHue0&lt;br /&gt;
!EndPaletteEffetID = !PaletteEffectIDHue31&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #!Delay&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!EndPaletteEffetID&lt;br /&gt;
    BCS .Restart&lt;br /&gt;
    INC A&lt;br /&gt;
    BRA .Store&lt;br /&gt;
.Restart&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
.Store&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: colores afectados.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;: separación entre cambios. &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; cambia cada frame, &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; cada dos, &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; cada cuatro y &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; cada ocho. Utiliza únicamente los valores indicados en el comentario.&lt;br /&gt;
* &amp;lt;code&amp;gt;!StartingPaletteEffetID&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EndPaletteEffetID&amp;lt;/code&amp;gt;: primer y último efecto del ciclo. Deben pertenecer a una secuencia de IDs consecutivos, con el inicio menor o igual que el final.&lt;br /&gt;
&lt;br /&gt;
El ciclo muestra el último ID antes de volver al primero. Conserva el uso de &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; del original para marcar el momento de los cambios; por ello, el primer intervalo depende del valor que tenga ese contador al entrar al nivel. Si quieres detenerlo al congelarse la acción, comprueba también &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt; al comienzo de &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDHue0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDHue31&amp;lt;/code&amp;gt; se generan desde el &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores; en este caso conserva &amp;lt;code&amp;gt;Hue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Hacer una transición que se detiene al terminar ===&lt;br /&gt;
&lt;br /&gt;
El código &amp;lt;code&amp;gt;GlobalPaletteEffect Transition&amp;lt;/code&amp;gt; avanza desde el efecto inicial hasta el final y conserva ese último resultado. Mantiene la configuración original de paletas, color fijo, velocidad y rango de IDs.&lt;br /&gt;
&lt;br /&gt;
Guarda esta versión de &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DynamicXtreme/Night.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 0, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 4, &amp;quot;Ratio2&amp;quot;: 4, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 8, &amp;quot;Ratio2&amp;quot;: 8, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 12, &amp;quot;Ratio2&amp;quot;: 12, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 16, &amp;quot;Ratio2&amp;quot;: 16, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 20, &amp;quot;Ratio2&amp;quot;: 20, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 25, &amp;quot;Ratio2&amp;quot;: 25, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 29, &amp;quot;Ratio2&amp;quot;: 29, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 33, &amp;quot;Ratio2&amp;quot;: 33, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 37, &amp;quot;Ratio2&amp;quot;: 37, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 41, &amp;quot;Ratio2&amp;quot;: 41, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 45, &amp;quot;Ratio2&amp;quot;: 45, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 49, &amp;quot;Ratio2&amp;quot;: 49, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 53, &amp;quot;Ratio2&amp;quot;: 53, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 57, &amp;quot;Ratio2&amp;quot;: 57, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 61, &amp;quot;Ratio2&amp;quot;: 61, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 66, &amp;quot;Ratio2&amp;quot;: 66, &amp;quot;EffectType&amp;quot;: 2}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Estos son los mismos 17 pasos del original. &amp;lt;code&amp;gt;EffectType = 2&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixRG&amp;lt;/code&amp;gt;: reduce el rojo y el verde sin modificar el azul. Los ratios antiguos 0-16 pasan aproximadamente a 0-66; no se amplían hasta 127 porque eso haría el cambio más intenso que en el archivo original.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Night.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 1&lt;br /&gt;
!P2 = 1&lt;br /&gt;
!P3 = 1&lt;br /&gt;
!P4 = 1&lt;br /&gt;
!P5 = 1&lt;br /&gt;
!P6 = 1&lt;br /&gt;
!P7 = 1&lt;br /&gt;
&lt;br /&gt;
!P8 = 1&lt;br /&gt;
!P9 = 1&lt;br /&gt;
!PA = 1&lt;br /&gt;
!PB = 1&lt;br /&gt;
!PC = 1&lt;br /&gt;
!PD = 1&lt;br /&gt;
!PE = 1&lt;br /&gt;
!PF = 1&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Valores permitidos: $00, $01, $03, $07, $0F, $1F, $3F, $7F y $FF.&lt;br /&gt;
!Delay = $03&lt;br /&gt;
&lt;br /&gt;
!StartingPaletteEffetID = !PaletteEffectIDNight0&lt;br /&gt;
!EndPaletteEffetID = !PaletteEffectIDNight16&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #!Delay&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!EndPaletteEffetID&lt;br /&gt;
    BCS .Finished&lt;br /&gt;
    INC A&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
.Finished&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: colores afectados.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;: tiempo entre cambios, con los mismos valores permitidos en el ejemplo de ciclo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!StartingPaletteEffetID&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EndPaletteEffetID&amp;lt;/code&amp;gt;: primer y último efecto. Deben ser IDs consecutivos en orden ascendente.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDNight16&amp;lt;/code&amp;gt; se generan desde &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres usan PascalCase eliminando separadores; aquí se conserva &amp;lt;code&amp;gt;Night&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para actualizar otros archivos antiguos, convierte cada ratio con &amp;lt;code&amp;gt;ratio antiguo × 127 ÷ 31&amp;lt;/code&amp;gt;, redondeando al entero más cercano, y utiliza el &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; correspondiente. No multipliques los valores &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt;: siguen utilizando 0-31.&lt;br /&gt;
&lt;br /&gt;
Este ejemplo cambia entre efectos de mezcla, igual que el original. Para una transición hacia otra paleta completa, utiliza &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt;, explicados en [[es/Dynamic_Xtreme_files_and_formats#Transiciones_de_paleta|Archivos y formatos]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21360</id>
		<title>es/Dynamic Xtreme UberASM guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21360"/>
		<updated>2026-10-24T22:48:12Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_UberASM_guide}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo utilizar Dynamic Xtreme desde UberASM para configurar los recursos de un nivel y crear cambios de gráficos y colores durante el juego. Se incluyen ejemplos para reservar paletas, elegir el espacio disponible para sprites dinámicos, crear animaciones y modificar los gráficos del jugador.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Tener UberASMTool instalado y configurado para insertar códigos en tu ROM.&lt;br /&gt;
* Tener Dynamic Xtreme instalado con las funciones necesarias para el ejemplo que quieras utilizar. Consulta la [[es/Dynamic_Xtreme_Quick_Start|guía de inicio rápido]] para su instalación.&lt;br /&gt;
&lt;br /&gt;
Para consultar los parámetros de una llamada o el uso de una variable, utiliza la [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]].&lt;br /&gt;
&lt;br /&gt;
== Preparar los ejemplos ==&lt;br /&gt;
&lt;br /&gt;
Cada ejemplo es independiente. Guarda el código de nivel en la carpeta correspondiente de UberASMTool y añádelo a su lista. Si reúnes varios ejemplos en un archivo, combina sus bloques &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; para no repetir las mismas etiquetas.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt; prepara datos durante la carga del nivel. Se utiliza aquí para reservar paletas antes de que las reclamen los sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; prepara las opciones al entrar al nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; ejecuta el código durante el juego, una vez por frame.&lt;br /&gt;
&lt;br /&gt;
Los defines y macros de Dynamic Xtreme deben estar disponibles en UberASMTool mediante la integración realizada durante la instalación. Si utilizas gráficos, paletas o efectos adicionales, decláralos en el ASM mediante los includes correspondientes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MyResources.dynamicinfo&amp;quot;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/MyEffect.paleffect&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las rutas son relativas al ASM. Incluye únicamente los archivos que utiliza tu ejemplo. También puedes usar las carpetas tradicionales de Dynamic Xtreme, como se explica en [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
&lt;br /&gt;
Después de añadir o modificar estos recursos, instala primero Dynamic Xtreme y después UberASMTool. Si solo cambias la lógica del ASM, basta con volver a ejecutar UberASMTool.&lt;br /&gt;
&lt;br /&gt;
== Reservar paletas para otros recursos ==&lt;br /&gt;
&lt;br /&gt;
Si una animación, un HUD u otro recurso necesita una paleta fija, conviene reservarla para que Dynamic Xtreme no la elija al asignar colores a los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
Para reservarla, escribe &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; en su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt;. Cada entrada ocupa 2 bytes. Por ejemplo, la paleta 9 utiliza el desplazamiento &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;: 9 × 2.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$FFFE&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_ID+$12    ; Reservar la paleta 9&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para reservar varias, escribe el mismo valor en sus entradas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Paleta !! Desplazamiento&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| A || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| B || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| C || &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| D || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| E || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| F || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La reserva impide que la asignación automática reclame esa paleta; no carga colores por sí misma. Un recurso configurado para utilizarla manualmente todavía puede cambiar sus colores, por lo que no debes asignársela también a otro recurso que necesite una paleta diferente.&lt;br /&gt;
&lt;br /&gt;
== Elegir el espacio de VRAM para sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Los sprites dinámicos necesitan una parte de VRAM donde cargar sus poses. Elige un espacio que no estés utilizando para gráficos fijos del nivel.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para permitir que utilicen SP4:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si necesitas más espacio y el nivel lo permite, puedes elegir &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; para SP3 y SP4, o &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt; para SP2, SP3 y SP4. Hay más opciones, incluidas medias páginas y configuraciones para compartir espacio con el jugador o DSX.&lt;br /&gt;
&lt;br /&gt;
Los defines disponibles están en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y en la [[es/Dynamic_Xtreme_ASM_API#Configuraciones_de_espacio_para_poses_dinámicas|tabla de configuraciones de la API]]. Configura el espacio antes de que el nivel empiece a cargar poses; cambiarlo no elimina automáticamente las poses que ya estaban en VRAM.&lt;br /&gt;
&lt;br /&gt;
== Configurar la cantidad de datos que se transfieren por frame ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; indica cuántos bytes pueden programar las cargas normales de Dynamic Xtreme durante un frame. Lo comparten las poses dinámicas, las animaciones y las demás transferencias realizadas con sus macros.&lt;br /&gt;
&lt;br /&gt;
El valor predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Este ejemplo lo aumenta a &amp;lt;code&amp;gt;$0A00&amp;lt;/code&amp;gt;, equivalente a 2560 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0A00&lt;br /&gt;
    STA.l DX_Dynamic_MaxDataPerFrame&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Subirlo permite intentar más cargas durante el mismo frame, pero no aumenta el tiempo que tiene SNES para copiarlas. Si la cantidad total es excesiva, pueden aparecer problemas visuales. Ajusta el valor según el nivel y comprueba el resultado con sus sprites y animaciones funcionando juntos.&lt;br /&gt;
&lt;br /&gt;
Las macros normales devuelven el carry desactivado si una carga no cabe en el límite. En ese caso, conserva lo que ya se muestra y vuelve a intentarlo después. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; se saltan la comprobación y también suman sus bytes al total.&lt;br /&gt;
&lt;br /&gt;
== Crear animaciones de gráficos ==&lt;br /&gt;
&lt;br /&gt;
Este código conserva el funcionamiento del ejemplo &amp;lt;code&amp;gt;Exanimation&amp;lt;/code&amp;gt;: una tabla indica dónde empieza cada imagen, un temporizador controla cuándo cambiarla y la imagen anterior se mantiene si no se acepta la transferencia.&lt;br /&gt;
&lt;br /&gt;
Declara los archivos del ejemplo en &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; RAM para el estado de la animación: comprobar que esté disponible.&lt;br /&gt;
!CurrentPoseIndex = $58&lt;br /&gt;
!AnimationTimer = $5C&lt;br /&gt;
!PaletteLoaded = $5D&lt;br /&gt;
&lt;br /&gt;
; Frames de espera antes de intentar el siguiente cambio.&lt;br /&gt;
!TimePerPose = $03&lt;br /&gt;
&lt;br /&gt;
; Bytes de cada imagen: un tile de 8x8 en 4bpp ocupa $0020.&lt;br /&gt;
!DataSend = $0200&lt;br /&gt;
&lt;br /&gt;
; Cantidad de imágenes utilizadas.&lt;br /&gt;
!NumberOfPoses = $05&lt;br /&gt;
&lt;br /&gt;
; Origen: recurso instalado. También puedes usar !AN2Buffer2.&lt;br /&gt;
!Source = !ResourceSMMArrow&lt;br /&gt;
&lt;br /&gt;
; Dirección de destino en VRAM.&lt;br /&gt;
!Destination = !BG2Line0&lt;br /&gt;
&lt;br /&gt;
; Paleta instalada y primer color de destino.&lt;br /&gt;
!Palette = &amp;quot;SMMArrowPal&amp;quot;&lt;br /&gt;
!PaletteDestination = $71&lt;br /&gt;
&lt;br /&gt;
; 0 = sin efecto global; 1 = recibe el efecto global.&lt;br /&gt;
!PaletteGlobalEffect = 0&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    STZ !CurrentPoseIndex&lt;br /&gt;
    LDA #!TimePerPose&lt;br /&gt;
    STA !AnimationTimer&lt;br /&gt;
    STZ !PaletteLoaded&lt;br /&gt;
&lt;br /&gt;
    %ForcedTransferToVRAM(#!Destination, #!Source, #((!Source&amp;gt;&amp;gt;16)&amp;amp;$FF), #!DataSend)&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteLoaded&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; Reintentar la paleta si no se aceptó durante init.&lt;br /&gt;
    LDA !PaletteLoaded&lt;br /&gt;
    BNE .Animate&lt;br /&gt;
    %TransferPaletteResource(!Palette, #!PaletteDestination, !PaletteGlobalEffect)&lt;br /&gt;
    BCS .PaletteReady&lt;br /&gt;
    RTL&lt;br /&gt;
.PaletteReady&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !PaletteLoaded&lt;br /&gt;
&lt;br /&gt;
.Animate&lt;br /&gt;
    LDA !AnimationTimer&lt;br /&gt;
    BEQ .NextPose&lt;br /&gt;
    DEC !AnimationTimer&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
.NextPose&lt;br /&gt;
    LDA !CurrentPoseIndex&lt;br /&gt;
    INC A&lt;br /&gt;
    CMP #!NumberOfPoses&lt;br /&gt;
    BCC .SelectPose&lt;br /&gt;
    LDA #$00&lt;br /&gt;
.SelectPose&lt;br /&gt;
    STA $05&lt;br /&gt;
    ASL&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l PosesTable,x&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC.w #!Source&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    %TransferToVRAM(#!Destination, $00, #((!Source&amp;gt;&amp;gt;16)&amp;amp;$FF), #!DataSend)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA $05&lt;br /&gt;
    STA !CurrentPoseIndex&lt;br /&gt;
    LDA #!TimePerPose&lt;br /&gt;
    STA !AnimationTimer&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
PosesTable:&lt;br /&gt;
    dw $0000&lt;br /&gt;
    dw !DataSend*$01&lt;br /&gt;
    dw !DataSend*$02&lt;br /&gt;
    dw !DataSend*$03&lt;br /&gt;
    dw !DataSend*$04&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!TimePerPose&amp;lt;/code&amp;gt;: tiempo de espera. Con &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;, el cambio se intenta cada cuatro frames: tres para descontar el temporizador y uno para realizar el cambio.&lt;br /&gt;
* &amp;lt;code&amp;gt;!DataSend&amp;lt;/code&amp;gt;: bytes de cada imagen. &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; equivale a 16 tiles de 8×8 en 4bpp.&lt;br /&gt;
* &amp;lt;code&amp;gt;!NumberOfPoses&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PosesTable&amp;lt;/code&amp;gt;: cantidad de imágenes y sus desplazamientos dentro del origen. El ejemplo utiliza las primeras cinco imágenes de &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;. Si añades más, amplía también la tabla.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Source&amp;lt;/code&amp;gt;: dirección de los gráficos. El ejemplo lee directamente &amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt;; para animar gráficos ya preparados por Lunar Magic puedes usar &amp;lt;code&amp;gt;!AN2Buffer2&amp;lt;/code&amp;gt;, como en el código original.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Destination&amp;lt;/code&amp;gt;: zona de VRAM que se actualizará. Coloca en el nivel tiles que utilicen esa zona y comprueba que otro recurso no la sobrescriba.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteDestination&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteGlobalEffect&amp;lt;/code&amp;gt;: paleta, primer color de destino y participación en el efecto global.&lt;br /&gt;
&lt;br /&gt;
Las direcciones de RAM del principio deben estar disponibles durante todo el nivel. No son scratch temporales: cambia esos defines si otro código ya las utiliza. &amp;lt;code&amp;gt;!PaletteLoaded&amp;lt;/code&amp;gt; permite reintentar una carga de paleta rechazada sin repetirla después de que haya sido aceptada.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt; se generan al instalar el DynamicInfo y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres se normalizan en PascalCase eliminando separadores; en este caso se conservan las mayúsculas de &amp;lt;code&amp;gt;SMMArrow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Todas las imágenes utilizadas deben quedar en el mismo banco del origen. La carga inicial de gráficos utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;; los siguientes cambios respetan el límite de datos por frame. Si una carga se rechaza, el código conserva la imagen anterior y vuelve a intentarla en el siguiente frame, sin avanzar el índice ni reiniciar el temporizador.&lt;br /&gt;
&lt;br /&gt;
Como en el original, el temporizador avanza cada vez que se ejecuta &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;. Si quieres detener la animación durante la pausa o cuando se congela la acción, puedes comprobar &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; antes de descontarlo.&lt;br /&gt;
&lt;br /&gt;
== Cambiar paletas durante el juego ==&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; permiten cargar colores y mantener actualizadas las copias que utilizan SMW y Dynamic Xtreme. También se encargan de preparar los efectos de paleta, por lo que no necesitas copiar buffers ni borrar indicadores a mano.&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza &amp;lt;code&amp;gt;SMMArrowPal.bin&amp;lt;/code&amp;gt;, un archivo de 15 colores (&amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes), y cambia los colores 1-F de la paleta 7. El color 0 queda sin modificar.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;, declara los gráficos como recurso general y la paleta en &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ASM del nivel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    ; Paleta 7, desde el color 1, con efecto global.&lt;br /&gt;
    %TransferPaletteResource(SMMArrowPal, #$71, 1)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El último parámetro elige cómo se carga la paleta:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;: prepara los colores originales para que reciban el efecto global antes de mostrarse. También deja la paleta preparada si todavía no has seleccionado un efecto.&lt;br /&gt;
* &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;: carga los colores sin efecto global y excluye esa paleta del efecto. Además actualiza los buffers de SMW, necesarios para evitar problemas de colores durante la animación de victoria del goal.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para cargar la misma paleta sin efecto global, utiliza esta llamada en lugar de la anterior:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferPaletteResource(SMMArrowPal, #$71, 0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si los efectos están deshabilitados en la instalación, ambas opciones realizan una carga directa. Cuando están habilitados y utilizas &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, el sistema carga el resultado ya procesado; no se muestra primero la paleta sin efecto durante un frame.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; utiliza los defines &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt;, generados desde &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; del DynamicInfo y publicados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra. En este caso se conserva &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; tal como está escrito.&lt;br /&gt;
&lt;br /&gt;
Para cambiar los colores durante el juego, llama a la macro desde &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; cuando corresponda, no en cada frame si la paleta no cambia. En una carga directa, el carry queda desactivado si no se pudo programar la transferencia: vuelve a intentarlo después. Con efecto global, el carry activado indica que los colores originales quedaron preparados, no que el resultado ya esté en pantalla.&lt;br /&gt;
&lt;br /&gt;
La opción de efecto se aplica a toda la paleta de 16 colores. Si cargas colores para recibir un efecto global, prepara todos sus colores visibles, como los 15 de este ejemplo; no cambies solo unos pocos esperando conservar una base que todavía no has preparado.&lt;br /&gt;
&lt;br /&gt;
Si eliges una paleta de sprites 8-F para un uso fijo, resérvala primero como se explica al comienzo del artículo. Estas macros no realizan asignación automática. Para cargar desde una dirección, un puntero o una tabla, consulta [[es/Dynamic_Xtreme_ASM_API#Cargar_colores_con_TransferPalette|Cargar colores con TransferPalette en la API]].&lt;br /&gt;
&lt;br /&gt;
== Cambiar los gráficos del jugador ==&lt;br /&gt;
&lt;br /&gt;
El ejemplo &amp;lt;code&amp;gt;Player Change&amp;lt;/code&amp;gt; alterna entre el jugador original y Geno al pulsar arriba. Conserva sus defines para elegir los gráficos y las cuatro paletas: Mario, Luigi, Mario con fuego y Luigi con fuego. También vuelve a seleccionar la paleta cuando cambia el estado del jugador.&lt;br /&gt;
&lt;br /&gt;
Necesita &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; habilitado. Los gráficos personalizados deben utilizar la misma organización de poses que los originales; cambiar el origen no adapta un spritesheet de otro formato.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/Geno.dynamicinfo&amp;lt;/code&amp;gt;, declara:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    Geno.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    GenoPal.bin&lt;br /&gt;
    GenoPalPlayer2.bin&lt;br /&gt;
    FireGenoPal.bin&lt;br /&gt;
    FireGenoPalPlayer2.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/Geno.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Dos bytes de RAM: comprobar que estén disponibles.&lt;br /&gt;
!Last0D82 = $18C7|!addr&lt;br /&gt;
&lt;br /&gt;
; Gráficos del jugador personalizado.&lt;br /&gt;
!PlayerGFXResource = !ResourceGeno&lt;br /&gt;
&lt;br /&gt;
; Paletas: jugador 1, jugador 2 y sus variantes con fuego.&lt;br /&gt;
!PlayerGFXPalette = !PaletteGenoPal&lt;br /&gt;
!PlayerGFXPalettePlayer2 = !PaletteGenoPalPlayer2&lt;br /&gt;
!PlayerGFXFirePalette = !PaletteFireGenoPal&lt;br /&gt;
!PlayerGFXFirePalettePlayer2 = !PaletteFireGenoPalPlayer2&lt;br /&gt;
&lt;br /&gt;
; Botón de cambio: $08 = arriba.&lt;br /&gt;
!ChangeButton = $08&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA !Last0D82&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA !ButtonDown_BYETUDLR&lt;br /&gt;
    AND #!ChangeButton&lt;br /&gt;
    BNE .Change&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    CMP !Last0D82&lt;br /&gt;
    BNE .Reload&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
.Change&lt;br /&gt;
    LDA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    CMP.b #!GFX32Buffer&amp;gt;&amp;gt;16&lt;br /&gt;
    BEQ .ChooseGeno&lt;br /&gt;
    JMP .Mario&lt;br /&gt;
.ChooseGeno&lt;br /&gt;
    JMP .Geno&lt;br /&gt;
&lt;br /&gt;
.Reload&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    CMP.b #!GFX32Buffer&amp;gt;&amp;gt;16&lt;br /&gt;
    BNE .Geno&lt;br /&gt;
    JMP .Mario&lt;br /&gt;
&lt;br /&gt;
.Geno&lt;br /&gt;
    ; Obtener 0, 1, 2 o 3 según jugador y estado de fuego.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    SEC&lt;br /&gt;
    SBC #!PlayerBasePalette&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    %DivW($01, $00, #$14)&lt;br /&gt;
&lt;br /&gt;
    ; Cada dirección de GenoPals ocupa tres bytes.&lt;br /&gt;
    LDA !DivisionResult&lt;br /&gt;
    ASL&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC !DivisionResult&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    ; Conservar el origen elegido y preparar los colores 2-5.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l GenoPals,x&lt;br /&gt;
    STA $03&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$0002&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.l GenoPals+2,x&lt;br /&gt;
    STA $02&lt;br /&gt;
    STA $05&lt;br /&gt;
&lt;br /&gt;
    %TransferPaletteFromPointer($00, #$82, $0008, 0)&lt;br /&gt;
    BCS .ApplyGeno&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.ApplyGeno&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!PlayerGFXResource&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!PlayerGFXResource&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
&lt;br /&gt;
    ; La rutina del jugador carga los colores 6-F.&lt;br /&gt;
    LDA $03&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC #$000A&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA $05&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    JMP .ConfirmSelection&lt;br /&gt;
&lt;br /&gt;
.Mario&lt;br /&gt;
    %TransferPaletteFromAddress(!PlayerPaletteColor2To5, #$82, $0008, 0)&lt;br /&gt;
    BCS .ApplyMario&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.ApplyMario&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!GFX32Buffer&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    LDA.w #(!GFX32Buffer&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
.ConfirmSelection&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA $0D82|!addr&lt;br /&gt;
    STA !Last0D82&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
GenoPals:&lt;br /&gt;
    dl !PlayerGFXPalette&lt;br /&gt;
    dl !PlayerGFXPalettePlayer2&lt;br /&gt;
    dl !PlayerGFXFirePalette&lt;br /&gt;
    dl !PlayerGFXFirePalettePlayer2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!PlayerGFXResource&amp;lt;/code&amp;gt;: gráficos del personaje personalizado.&lt;br /&gt;
* Los cuatro defines &amp;lt;code&amp;gt;!PlayerGFX...Palette...&amp;lt;/code&amp;gt;: direcciones de sus paletas, en el orden de la tabla &amp;lt;code&amp;gt;GenoPals&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!ChangeButton&amp;lt;/code&amp;gt;: botón que alterna entre los personajes. Utiliza los bits del control &amp;lt;code&amp;gt;BYETUDLR&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; corresponde a arriba.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Last0D82&amp;lt;/code&amp;gt;: dos bytes de RAM para recordar la selección de paleta del juego. Asegúrate de que ningún otro código los utilice.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGeno&amp;lt;/code&amp;gt; y los defines &amp;lt;code&amp;gt;!PaletteGenoPal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteGenoPalPlayer2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteFireGenoPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteFireGenoPalPlayer2&amp;lt;/code&amp;gt; se generan desde el DynamicInfo y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres usan PascalCase eliminando espacios, guiones y guiones bajos, y conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
El código mantiene el formato de las paletas del paquete: cada archivo contiene los colores 1-F. Se omite su primer color para copiar los colores 2-5; los últimos diez comienzan en &amp;lt;code&amp;gt;+$0A&amp;lt;/code&amp;gt; y los utiliza la rutina del jugador.&lt;br /&gt;
&lt;br /&gt;
Las cargas de los colores 2-5 ahora utilizan &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, que también actualiza los buffers de SMW. El ejemplo no confirma el cambio de gráficos si esa transferencia es rechazada. Un cambio pendiente por el estado del jugador se vuelve a intentar mientras no coincida con &amp;lt;code&amp;gt;!Last0D82&amp;lt;/code&amp;gt;; si se rechaza un cambio solicitado con el botón, vuelve a pulsarlo.&lt;br /&gt;
&lt;br /&gt;
Como en el paquete original, el código distingue al jugador original por el banco de &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt;. Si lo adaptas para alternar entre varios personajes personalizados en ROM, necesitarás otra forma de recordar cuál está seleccionado.&lt;br /&gt;
&lt;br /&gt;
Este ejemplo carga la paleta del jugador sin efecto global. No basta con cambiar a &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; el parámetro de una carga de cuatro colores para añadirle un efecto: en ese caso hay que preparar todos los colores visibles de la paleta 8 y respetar su carga especial.&lt;br /&gt;
&lt;br /&gt;
== Aplicar un efecto global de paleta ==&lt;br /&gt;
&lt;br /&gt;
Los tres ejemplos de efectos conservan los ajustes del paquete: puedes elegir cada paleta por separado, incluir el color fijo y seleccionar los IDs de inicio y final. Los códigos de ciclo y transición también permiten configurar la velocidad con &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los archivos &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; siguientes conservan la cantidad y el orden de efectos de los originales. Se actualizan al formato actual usando &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; y convirtiendo los ratios de 0-31 a 0-127. Los valores &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt; continúan entre 0 y 31.&lt;br /&gt;
&lt;br /&gt;
=== Elegir las paletas afectadas ===&lt;br /&gt;
&lt;br /&gt;
En cada código, cambia &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt; a 1 para incluir la paleta correspondiente o a 0 para excluirla. &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; controla el color fijo y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt; permite incluir también el color 0,0.&lt;br /&gt;
&lt;br /&gt;
Las máscaras &amp;lt;code&amp;gt;!EnableBG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableSP&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColors&amp;lt;/code&amp;gt; se calculan a partir de esos ajustes. No necesitas modificarlas a mano. En la API actual, el bit bajo corresponde a la primera paleta de cada grupo:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor del bit !! Paleta de fondo !! Paleta de sprites&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || 0 || 8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || 1 || 9&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || 2 || A&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || 3 || B&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || 4 || C&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || 5 || D&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || 6 || E&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; || 7 || F&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
El color fijo y el color 0,0 utilizan &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt;: bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; y bit &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, respectivamente. Esto sustituye la variable antigua &amp;lt;code&amp;gt;DX_PPU_FixedColor_Enable&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
En sprites con asignación dinámica, configura también el bit E de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;. Si cargas paletas mediante &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt;, su último parámetro determina si esas paletas participan en el efecto global. Evita que otro código vuelva a escribir máscaras distintas sin tener en cuenta esa configuración.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto fijo ===&lt;br /&gt;
&lt;br /&gt;
El código &amp;lt;code&amp;gt;SimpleGlobalPaletteEffect&amp;lt;/code&amp;gt; aplica el efecto que indiques en &amp;lt;code&amp;gt;!PaletteEffetID&amp;lt;/code&amp;gt;. Esta es su configuración original: todas las paletas y el color fijo habilitados, con el último efecto de &amp;lt;code&amp;gt;DecreaseSaturation&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Guarda esta versión actualizada de &amp;lt;code&amp;gt;DecreaseSaturation.paleffect&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DynamicXtreme/DecreaseSaturation.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 4, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 8, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 12, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 16, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 20, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 25, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 29, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 33, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 37, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 41, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 45, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 49, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 53, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 57, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 61, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 66, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 70, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 74, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 78, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 82, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 86, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 90, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 94, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 98, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 102, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 107, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 111, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 115, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 119, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 123, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 11},&lt;br /&gt;
    {&amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 11}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Se conservan sus 32 entradas, incluida la última repetida. &amp;lt;code&amp;gt;EffectType = 11&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;Channel2 = 0&amp;lt;/code&amp;gt; indica que se reduce la saturación y &amp;lt;code&amp;gt;Ratio2&amp;lt;/code&amp;gt; controla cuánto. El último efecto utiliza 127, que aplica el cambio completo.&lt;br /&gt;
&lt;br /&gt;
El ASM actualizado es:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/DecreaseSaturation.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 1&lt;br /&gt;
!P2 = 1&lt;br /&gt;
!P3 = 1&lt;br /&gt;
!P4 = 1&lt;br /&gt;
!P5 = 1&lt;br /&gt;
!P6 = 1&lt;br /&gt;
!P7 = 1&lt;br /&gt;
&lt;br /&gt;
!P8 = 1&lt;br /&gt;
!P9 = 1&lt;br /&gt;
!PA = 1&lt;br /&gt;
!PB = 1&lt;br /&gt;
!PC = 1&lt;br /&gt;
!PD = 1&lt;br /&gt;
!PE = 1&lt;br /&gt;
!PF = 1&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Efecto que se aplica al entrar al nivel.&lt;br /&gt;
!PaletteEffetID = !PaletteEffectIDDecreaseSaturation31&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;: paletas afectadas.&lt;br /&gt;
* &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: participación de esos colores.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteEffetID&amp;lt;/code&amp;gt;: efecto seleccionado. Puedes utilizar cualquier ID generado desde tu archivo de efectos, no solo el último de este ejemplo.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation31&amp;lt;/code&amp;gt; se generan desde el &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando espacios, guiones y guiones bajos, y conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
La selección se realiza en &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;; no hace falta repetirla cada frame. Para quitar el efecto, escribe 0 en el ID global y deja las paletas habilitadas para que el sistema restaure sus colores originales:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hacer que el efecto se repita en un ciclo ===&lt;br /&gt;
&lt;br /&gt;
El código &amp;lt;code&amp;gt;GlobalPaletteEffect Cycle&amp;lt;/code&amp;gt; recorre una secuencia de efectos y vuelve al primero. Conserva sus opciones de velocidad, primer y último ID y selección de paletas. Como en el original, la configuración inicial incluye solo la paleta 0 y el color fijo.&lt;br /&gt;
&lt;br /&gt;
Guarda esta versión de &amp;lt;code&amp;gt;Hue.paleffect&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DynamicXtreme/Hue.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 1, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 2, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 3, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 4, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 5, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 6, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 7, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 8, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 9, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 10, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 11, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 12, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 13, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 14, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 15, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 16, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 17, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 18, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 19, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 20, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 21, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 22, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 23, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 24, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 25, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 26, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 27, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 28, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 29, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 30, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 31, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 31, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Se conservan los 32 efectos del archivo original, con el tono 31 repetido al final. &amp;lt;code&amp;gt;EffectType = 9&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Ratio1 = 127&amp;lt;/code&amp;gt; aplica por completo el tono seleccionado.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Hue.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 0&lt;br /&gt;
!P2 = 0&lt;br /&gt;
!P3 = 0&lt;br /&gt;
!P4 = 0&lt;br /&gt;
!P5 = 0&lt;br /&gt;
!P6 = 0&lt;br /&gt;
!P7 = 0&lt;br /&gt;
&lt;br /&gt;
!P8 = 0&lt;br /&gt;
!P9 = 0&lt;br /&gt;
!PA = 0&lt;br /&gt;
!PB = 0&lt;br /&gt;
!PC = 0&lt;br /&gt;
!PD = 0&lt;br /&gt;
!PE = 0&lt;br /&gt;
!PF = 0&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Valores permitidos: $00, $01, $03, $07, $0F, $1F, $3F, $7F y $FF.&lt;br /&gt;
!Delay = $03&lt;br /&gt;
&lt;br /&gt;
!StartingPaletteEffetID = !PaletteEffectIDHue0&lt;br /&gt;
!EndPaletteEffetID = !PaletteEffectIDHue31&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #!Delay&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!EndPaletteEffetID&lt;br /&gt;
    BCS .Restart&lt;br /&gt;
    INC A&lt;br /&gt;
    BRA .Store&lt;br /&gt;
.Restart&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
.Store&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: colores afectados.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;: separación entre cambios. &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; cambia cada frame, &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; cada dos, &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; cada cuatro y &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; cada ocho. Utiliza únicamente los valores indicados en el comentario.&lt;br /&gt;
* &amp;lt;code&amp;gt;!StartingPaletteEffetID&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EndPaletteEffetID&amp;lt;/code&amp;gt;: primer y último efecto del ciclo. Deben pertenecer a una secuencia de IDs consecutivos, con el inicio menor o igual que el final.&lt;br /&gt;
&lt;br /&gt;
El ciclo muestra el último ID antes de volver al primero. Conserva el uso de &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; del original para marcar el momento de los cambios; por ello, el primer intervalo depende del valor que tenga ese contador al entrar al nivel. Si quieres detenerlo al congelarse la acción, comprueba también &amp;lt;code&amp;gt;$9D&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$13D4|!addr&amp;lt;/code&amp;gt; al comienzo de &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDHue0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDHue31&amp;lt;/code&amp;gt; se generan desde el &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores; en este caso conserva &amp;lt;code&amp;gt;Hue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Hacer una transición que se detiene al terminar ===&lt;br /&gt;
&lt;br /&gt;
El código &amp;lt;code&amp;gt;GlobalPaletteEffect Transition&amp;lt;/code&amp;gt; avanza desde el efecto inicial hasta el final y conserva ese último resultado. Mantiene la configuración original de paletas, color fijo, velocidad y rango de IDs.&lt;br /&gt;
&lt;br /&gt;
Guarda esta versión de &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DynamicXtreme/Night.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 0, &amp;quot;Ratio2&amp;quot;: 0, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 4, &amp;quot;Ratio2&amp;quot;: 4, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 8, &amp;quot;Ratio2&amp;quot;: 8, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 12, &amp;quot;Ratio2&amp;quot;: 12, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 16, &amp;quot;Ratio2&amp;quot;: 16, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 20, &amp;quot;Ratio2&amp;quot;: 20, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 25, &amp;quot;Ratio2&amp;quot;: 25, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 29, &amp;quot;Ratio2&amp;quot;: 29, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 33, &amp;quot;Ratio2&amp;quot;: 33, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 37, &amp;quot;Ratio2&amp;quot;: 37, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 41, &amp;quot;Ratio2&amp;quot;: 41, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 45, &amp;quot;Ratio2&amp;quot;: 45, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 49, &amp;quot;Ratio2&amp;quot;: 49, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 53, &amp;quot;Ratio2&amp;quot;: 53, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 57, &amp;quot;Ratio2&amp;quot;: 57, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 61, &amp;quot;Ratio2&amp;quot;: 61, &amp;quot;EffectType&amp;quot;: 2},&lt;br /&gt;
    {&amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 66, &amp;quot;Ratio2&amp;quot;: 66, &amp;quot;EffectType&amp;quot;: 2}&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Estos son los mismos 17 pasos del original. &amp;lt;code&amp;gt;EffectType = 2&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;MixRG&amp;lt;/code&amp;gt;: reduce el rojo y el verde sin modificar el azul. Los ratios antiguos 0-16 pasan aproximadamente a 0-66; no se amplían hasta 127 porque eso haría el cambio más intenso que en el archivo original.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Night.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; 1 = incluir la paleta en el efecto; 0 = excluirla.&lt;br /&gt;
!P0 = 1&lt;br /&gt;
!P1 = 1&lt;br /&gt;
!P2 = 1&lt;br /&gt;
!P3 = 1&lt;br /&gt;
!P4 = 1&lt;br /&gt;
!P5 = 1&lt;br /&gt;
!P6 = 1&lt;br /&gt;
!P7 = 1&lt;br /&gt;
&lt;br /&gt;
!P8 = 1&lt;br /&gt;
!P9 = 1&lt;br /&gt;
!PA = 1&lt;br /&gt;
!PB = 1&lt;br /&gt;
!PC = 1&lt;br /&gt;
!PD = 1&lt;br /&gt;
!PE = 1&lt;br /&gt;
!PF = 1&lt;br /&gt;
&lt;br /&gt;
!EnableFixedColor = 1&lt;br /&gt;
!EnableColor00 = 0&lt;br /&gt;
&lt;br /&gt;
; Valores permitidos: $00, $01, $03, $07, $0F, $1F, $3F, $7F y $FF.&lt;br /&gt;
!Delay = $03&lt;br /&gt;
&lt;br /&gt;
!StartingPaletteEffetID = !PaletteEffectIDNight0&lt;br /&gt;
!EndPaletteEffetID = !PaletteEffectIDNight16&lt;br /&gt;
&lt;br /&gt;
; Máscaras calculadas: no hace falta modificarlas.&lt;br /&gt;
!EnableBG = !P0|(!P1&amp;lt;&amp;lt;1)|(!P2&amp;lt;&amp;lt;2)|(!P3&amp;lt;&amp;lt;3)|(!P4&amp;lt;&amp;lt;4)|(!P5&amp;lt;&amp;lt;5)|(!P6&amp;lt;&amp;lt;6)|(!P7&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableSP = !P8|(!P9&amp;lt;&amp;lt;1)|(!PA&amp;lt;&amp;lt;2)|(!PB&amp;lt;&amp;lt;3)|(!PC&amp;lt;&amp;lt;4)|(!PD&amp;lt;&amp;lt;5)|(!PE&amp;lt;&amp;lt;6)|(!PF&amp;lt;&amp;lt;7)&lt;br /&gt;
!EnableColors = !EnableFixedColor|(!EnableColor00&amp;lt;&amp;lt;1)&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!EnableBG&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #!EnableSP&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    LDA #!EnableColors&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!StartingPaletteEffetID&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #!Delay&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!EndPaletteEffetID&lt;br /&gt;
    BCS .Finished&lt;br /&gt;
    INC A&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
.Finished&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué puedes cambiar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!P0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PF&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!EnableFixedColor&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EnableColor00&amp;lt;/code&amp;gt;: colores afectados.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Delay&amp;lt;/code&amp;gt;: tiempo entre cambios, con los mismos valores permitidos en el ejemplo de ciclo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!StartingPaletteEffetID&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!EndPaletteEffetID&amp;lt;/code&amp;gt;: primer y último efecto. Deben ser IDs consecutivos en orden ascendente.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDNight16&amp;lt;/code&amp;gt; se generan desde &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres usan PascalCase eliminando separadores; aquí se conserva &amp;lt;code&amp;gt;Night&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para actualizar otros archivos antiguos, convierte cada ratio con &amp;lt;code&amp;gt;ratio antiguo × 127 ÷ 31&amp;lt;/code&amp;gt;, redondeando al entero más cercano, y utiliza el &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; correspondiente. No multipliques los valores &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt;: siguen utilizando 0-31.&lt;br /&gt;
&lt;br /&gt;
Este ejemplo cambia entre efectos de mezcla, igual que el original. Para una transición hacia otra paleta completa, utiliza &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt;, explicados en [[es/Dynamic_Xtreme_files_and_formats#Transiciones_de_paleta|Archivos y formatos]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21359</id>
		<title>es/Dynamic Xtreme UberASM guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21359"/>
		<updated>2026-10-24T22:41:37Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_UberASM_guide}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo utilizar Dynamic Xtreme desde UberASM para configurar los recursos de un nivel y crear cambios de gráficos y colores durante el juego. Se incluyen ejemplos para reservar paletas, elegir el espacio disponible para sprites dinámicos, crear animaciones y modificar los gráficos del jugador.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Tener UberASMTool instalado y configurado para insertar códigos en tu ROM.&lt;br /&gt;
* Tener Dynamic Xtreme instalado con las funciones necesarias para el ejemplo que quieras utilizar. Consulta la [[es/Dynamic_Xtreme_Quick_Start|guía de inicio rápido]] para su instalación.&lt;br /&gt;
&lt;br /&gt;
Para consultar los parámetros de una llamada o el uso de una variable, utiliza la [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]].&lt;br /&gt;
&lt;br /&gt;
== Preparar los ejemplos ==&lt;br /&gt;
&lt;br /&gt;
Cada ejemplo es independiente. Guarda el código de nivel en la carpeta correspondiente de UberASMTool y añádelo a su lista. Si reúnes varios ejemplos en un archivo, combina sus bloques &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; para no repetir las mismas etiquetas.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt; prepara datos durante la carga del nivel. Se utiliza aquí para reservar paletas antes de que las reclamen los sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; prepara las opciones al entrar al nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; ejecuta el código durante el juego, una vez por frame.&lt;br /&gt;
&lt;br /&gt;
Los defines y macros de Dynamic Xtreme deben estar disponibles en UberASMTool mediante la integración realizada durante la instalación. Si utilizas gráficos, paletas o efectos adicionales, decláralos en el ASM mediante los includes correspondientes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MyResources.dynamicinfo&amp;quot;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/MyEffect.paleffect&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las rutas son relativas al ASM. Incluye únicamente los archivos que utiliza tu ejemplo. También puedes usar las carpetas tradicionales de Dynamic Xtreme, como se explica en [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
&lt;br /&gt;
Después de añadir o modificar estos recursos, instala primero Dynamic Xtreme y después UberASMTool. Si solo cambias la lógica del ASM, basta con volver a ejecutar UberASMTool.&lt;br /&gt;
&lt;br /&gt;
== Reservar paletas para otros recursos ==&lt;br /&gt;
&lt;br /&gt;
Si una animación, un HUD u otro recurso necesita una paleta fija, conviene reservarla para que Dynamic Xtreme no la elija al asignar colores a los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
Para reservarla, escribe &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; en su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt;. Cada entrada ocupa 2 bytes. Por ejemplo, la paleta 9 utiliza el desplazamiento &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;: 9 × 2.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$FFFE&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_ID+$12    ; Reservar la paleta 9&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para reservar varias, escribe el mismo valor en sus entradas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Paleta !! Desplazamiento&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| A || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| B || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| C || &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| D || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| E || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| F || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La reserva impide que la asignación automática reclame esa paleta; no carga colores por sí misma. Un recurso configurado para utilizarla manualmente todavía puede cambiar sus colores, por lo que no debes asignársela también a otro recurso que necesite una paleta diferente.&lt;br /&gt;
&lt;br /&gt;
== Elegir el espacio de VRAM para sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Los sprites dinámicos necesitan una parte de VRAM donde cargar sus poses. Elige un espacio que no estés utilizando para gráficos fijos del nivel.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para permitir que utilicen SP4:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si necesitas más espacio y el nivel lo permite, puedes elegir &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; para SP3 y SP4, o &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt; para SP2, SP3 y SP4. Hay más opciones, incluidas medias páginas y configuraciones para compartir espacio con el jugador o DSX.&lt;br /&gt;
&lt;br /&gt;
Los defines disponibles están en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y en la [[es/Dynamic_Xtreme_ASM_API#Configuraciones_de_espacio_para_poses_dinámicas|tabla de configuraciones de la API]]. Configura el espacio antes de que el nivel empiece a cargar poses; cambiarlo no elimina automáticamente las poses que ya estaban en VRAM.&lt;br /&gt;
&lt;br /&gt;
== Configurar la cantidad de datos que se transfieren por frame ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; indica cuántos bytes pueden programar las cargas normales de Dynamic Xtreme durante un frame. Lo comparten las poses dinámicas, las animaciones y las demás transferencias realizadas con sus macros.&lt;br /&gt;
&lt;br /&gt;
El valor predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Este ejemplo lo aumenta a &amp;lt;code&amp;gt;$0A00&amp;lt;/code&amp;gt;, equivalente a 2560 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0A00&lt;br /&gt;
    STA.l DX_Dynamic_MaxDataPerFrame&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Subirlo permite intentar más cargas durante el mismo frame, pero no aumenta el tiempo que tiene SNES para copiarlas. Si la cantidad total es excesiva, pueden aparecer problemas visuales. Ajusta el valor según el nivel y comprueba el resultado con sus sprites y animaciones funcionando juntos.&lt;br /&gt;
&lt;br /&gt;
Las macros normales devuelven el carry desactivado si una carga no cabe en el límite. En ese caso, conserva lo que ya se muestra y vuelve a intentarlo después. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; se saltan la comprobación y también suman sus bytes al total.&lt;br /&gt;
&lt;br /&gt;
== Crear animaciones de gráficos ==&lt;br /&gt;
&lt;br /&gt;
Una animación de tiles se consigue copiando distintas imágenes al mismo lugar de VRAM. Los tiles del nivel siguen apuntando al mismo lugar, pero los gráficos que contienen van cambiando.&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las primeras cuatro imágenes de &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;, con &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes por imagen, y cambia de imagen cada ocho frames. El archivo se registra como recurso general, no como pose de sprite dinámico.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;, junto a &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ASM del nivel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
!AnimationGraphics = !ResourceSMMArrow&lt;br /&gt;
!Destination = !BG2Line0&lt;br /&gt;
!BytesPerFrame = $0200&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    %ForcedTransferToVRAMFromAddr(#!Destination, !AnimationGraphics, #!BytesPerFrame)&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $9D&lt;br /&gt;
    ORA $13D4|!addr&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    ; Cambiar de imagen cada ocho frames.&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$07&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    ; Obtener 0, $0200, $0400 o $0600 como desplazamiento en el archivo.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$0018&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC.w #!AnimationGraphics&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    %TransferToVRAM(#!Destination, $00, #(!AnimationGraphics&amp;gt;&amp;gt;16), #!BytesPerFrame)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt; es la dirección que se genera al instalar el recurso y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres se normalizan eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra. En este caso se conserva &amp;lt;code&amp;gt;SMMArrow&amp;lt;/code&amp;gt; tal como está escrito en el nombre del archivo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Destination&amp;lt;/code&amp;gt; elige dónde se muestran los gráficos. Aquí se usa &amp;lt;code&amp;gt;!BG2Line0&amp;lt;/code&amp;gt;; debes colocar en el nivel tiles que utilicen esa zona y asegurarte de que ningún otro recurso la sobrescriba. &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes equivalen a 16 tiles de 8×8 en gráficos de 4 bits por píxel.&lt;br /&gt;
&lt;br /&gt;
El cálculo de este ejemplo está hecho para cuatro imágenes de &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes. Cambiar el tamaño o la cantidad de imágenes requiere ajustar también ese cálculo. Las cuatro imágenes utilizadas deben estar en el mismo banco de origen, porque la transferencia recibe una dirección y un banco por separado.&lt;br /&gt;
&lt;br /&gt;
Si una transferencia normal se rechaza, permanece la imagen anterior y se intenta otra carga en el siguiente cambio de la animación. &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; permite detener la animación junto con el juego. La carga inicial utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; una sola vez; los cambios durante el juego respetan el límite de datos por frame.&lt;br /&gt;
&lt;br /&gt;
== Cambiar paletas durante el juego ==&lt;br /&gt;
&lt;br /&gt;
Las macros &amp;lt;code&amp;gt;TransferPalette&amp;lt;/code&amp;gt; permiten cargar colores y mantener actualizadas las copias que utilizan SMW y Dynamic Xtreme. También se encargan de preparar los efectos de paleta, por lo que no necesitas copiar buffers ni borrar indicadores a mano.&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza &amp;lt;code&amp;gt;SMMArrowPal.bin&amp;lt;/code&amp;gt;, un archivo de 15 colores (&amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes), y cambia los colores 1-F de la paleta 7. El color 0 queda sin modificar.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;, declara los gráficos como recurso general y la paleta en &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ASM del nivel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    ; Paleta 7, desde el color 1, con efecto global.&lt;br /&gt;
    %TransferPaletteResource(SMMArrowPal, #$71, 1)&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El último parámetro elige cómo se carga la paleta:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;: prepara los colores originales para que reciban el efecto global antes de mostrarse. También deja la paleta preparada si todavía no has seleccionado un efecto.&lt;br /&gt;
* &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;: carga los colores sin efecto global y excluye esa paleta del efecto. Además actualiza los buffers de SMW, necesarios para evitar problemas de colores durante la animación de victoria del goal.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para cargar la misma paleta sin efecto global, utiliza esta llamada en lugar de la anterior:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferPaletteResource(SMMArrowPal, #$71, 0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si los efectos están deshabilitados en la instalación, ambas opciones realizan una carga directa. Cuando están habilitados y utilizas &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, el sistema carga el resultado ya procesado; no se muestra primero la paleta sin efecto durante un frame.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; utiliza los defines &amp;lt;code&amp;gt;!PaletteSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteSMMArrowPalSize&amp;lt;/code&amp;gt;, generados desde &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; del DynamicInfo y publicados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra. En este caso se conserva &amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; tal como está escrito.&lt;br /&gt;
&lt;br /&gt;
Para cambiar los colores durante el juego, llama a la macro desde &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; cuando corresponda, no en cada frame si la paleta no cambia. En una carga directa, el carry queda desactivado si no se pudo programar la transferencia: vuelve a intentarlo después. Con efecto global, el carry activado indica que los colores originales quedaron preparados, no que el resultado ya esté en pantalla.&lt;br /&gt;
&lt;br /&gt;
La opción de efecto se aplica a toda la paleta de 16 colores. Si cargas colores para recibir un efecto global, prepara todos sus colores visibles, como los 15 de este ejemplo; no cambies solo unos pocos esperando conservar una base que todavía no has preparado.&lt;br /&gt;
&lt;br /&gt;
Si eliges una paleta de sprites 8-F para un uso fijo, resérvala primero como se explica al comienzo del artículo. Estas macros no realizan asignación automática. Para cargar desde una dirección, un puntero o una tabla, consulta [[es/Dynamic_Xtreme_ASM_API#Cargar_colores_con_TransferPalette|Cargar colores con TransferPalette en la API]].&lt;br /&gt;
&lt;br /&gt;
== Cambiar los gráficos del jugador ==&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; habilitado, puedes indicar desde qué archivo se leen los gráficos del jugador. El archivo debe utilizar la misma organización de poses que los gráficos originales de Mario; cambiar la dirección no adapta automáticamente un spritesheet de otro formato.&lt;br /&gt;
&lt;br /&gt;
Registra los gráficos como recurso general. Por ejemplo, con &amp;lt;code&amp;gt;Geno.bin&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Geno.dynamicinfo&amp;lt;/code&amp;gt; juntos:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    Geno.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/Geno.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!ResourceGeno&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!ResourceGeno&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Enable&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGeno&amp;lt;/code&amp;gt; se genera desde el recurso del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores; por ejemplo, &amp;lt;code&amp;gt;my_player&amp;lt;/code&amp;gt; produciría &amp;lt;code&amp;gt;MyPlayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El juego continúa eligiendo las poses del jugador normalmente, pero Dynamic Xtreme lee sus tiles desde el nuevo archivo. Este ejemplo cambia los gráficos, no la paleta ni el comportamiento del personaje.&lt;br /&gt;
&lt;br /&gt;
Para volver a los gráficos habituales, cambia el origen a &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!GFX32Buffer&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!GFX32Buffer&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
También puedes ejecutar estos cambios al pulsar un botón o al entrar en un estado concreto. No es necesario escribir la misma dirección en cada frame si no cambió el personaje.&lt;br /&gt;
&lt;br /&gt;
=== Cambiar también la paleta del jugador ===&lt;br /&gt;
&lt;br /&gt;
El jugador divide sus colores en partes. En el archivo de 15 colores del ejemplo de Geno, los colores 2-5 de la paleta 8 se cargan al cambiar de personaje, mientras la rutina del jugador toma los colores 6-F desde la dirección que indiques. La disposición del archivo debe coincidir con ese formato.&lt;br /&gt;
&lt;br /&gt;
Añade &amp;lt;code&amp;gt;GenoPal.bin&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; del DynamicInfo, junto a los gráficos declarados en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    Geno.bin&lt;br /&gt;
Palettes:&lt;br /&gt;
    GenoPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Este ejemplo configura la paleta de un jugador que no recibe efectos globales:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/Geno.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    ; Colores 2-5: omitir el primer color del archivo.&lt;br /&gt;
    %TransferPaletteFromAddress(!PaletteGenoPal+$02, #$82, $0008, 0)&lt;br /&gt;
    BCS .SetupPlayer&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.SetupPlayer&lt;br /&gt;
    ; Colores 6-F: la rutina del jugador los toma desde este origen.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!PaletteGenoPal+$0A&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.b #(!PaletteGenoPal+$0A)&amp;gt;&amp;gt;16&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Enable&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TransferPaletteFromAddress&amp;lt;/code&amp;gt; carga esos cuatro colores sin efecto global y actualiza los buffers y el estado de efectos necesarios. &amp;lt;code&amp;gt;$0008&amp;lt;/code&amp;gt; indica 8 bytes, es decir, 4 colores, y se escribe sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;. Si la transferencia no se acepta, el ejemplo termina sin cambiar el origen de la paleta del jugador; para realizar el cambio durante el juego, vuelve a intentarlo desde &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; cuando corresponda.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteGenoPal&amp;lt;/code&amp;gt; se genera al instalar la paleta declarada en el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre utiliza PascalCase eliminando separadores; en este caso se conservan las mayúsculas de &amp;lt;code&amp;gt;GenoPal&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Esta variante deja la paleta 8 fuera del efecto global. Para combinar la paleta del jugador con efectos globales hay que preparar todos sus colores visibles y tener en cuenta su carga especial; no basta con cambiar a &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; el último parámetro de esta carga de cuatro colores.&lt;br /&gt;
&lt;br /&gt;
Si el personaje utiliza colores distintos para Mario, Luigi o el estado de fuego, selecciona la paleta correspondiente antes de aplicar el cambio. El código de cambio de jugador del paquete utiliza una tabla de cuatro paletas para esa selección.&lt;br /&gt;
&lt;br /&gt;
== Aplicar un efecto global de paleta ==&lt;br /&gt;
&lt;br /&gt;
Un efecto global permite cambiar los colores de varias paletas con una sola selección. Primero defines el efecto en un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y después indicas desde UberASM qué paletas lo reciben.&lt;br /&gt;
&lt;br /&gt;
=== Preparar el efecto ===&lt;br /&gt;
&lt;br /&gt;
Este ejemplo elimina la saturación de los colores, utilizando &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt;. Guarda lo siguiente como &amp;lt;code&amp;gt;DynamicXtreme/DecreaseSaturation.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;Channel2&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;Ratio2&amp;quot;: 127,&lt;br /&gt;
      &amp;quot;EffectType&amp;quot;: 11&lt;br /&gt;
    }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Channel2 = 0&amp;lt;/code&amp;gt; indica la saturación a la que se quiere llegar y &amp;lt;code&amp;gt;Ratio2 = 127&amp;lt;/code&amp;gt; aplica el cambio completo. Los valores de color siguen estando entre 0 y 31; los ratios utilizan 0-127.&lt;br /&gt;
&lt;br /&gt;
Si adaptas un efecto antiguo cuyos ratios iban de 0 a 31, conserva la proporción del cambio: 0 sigue siendo 0, 31 pasa a 127 y un valor intermedio se convierte aproximadamente con &amp;lt;code&amp;gt;ratio antiguo × 127 ÷ 31&amp;lt;/code&amp;gt;, redondeando al entero más cercano. No multipliques los valores &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt;: siguen usando 0-31. Los archivos antiguos que utilizan &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; también deben indicar el &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; actual; por ejemplo, &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt; es 9, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; es 11 y &amp;lt;code&amp;gt;MixRG&amp;lt;/code&amp;gt; es 2.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo se genera &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation0&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El número final es el índice del efecto dentro del archivo, no su ratio. Los nombres se normalizan eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;decrease_saturation&amp;lt;/code&amp;gt; produciría &amp;lt;code&amp;gt;DecreaseSaturation&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Elegir las paletas afectadas ===&lt;br /&gt;
&lt;br /&gt;
Cada bit de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; permite el efecto en una paleta 0-7; &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; hace lo mismo para las paletas 8-F:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor del bit !! Paleta de fondo !! Paleta de sprites&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || 0 || 8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || 1 || 9&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || 2 || A&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || 3 || B&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || 4 || C&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || 5 || D&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || 6 || E&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; || 7 || F&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Puedes combinar bits para elegir varias. Por ejemplo, &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; selecciona las dos primeras y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; selecciona las ocho. En sprites con asignación dinámica, configura también el bit E de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; según quieras que su paleta participe en el efecto global.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto fijo ===&lt;br /&gt;
&lt;br /&gt;
El siguiente código aplica el efecto a las paletas de fondo 0-7. La máscara de sprites se deja en 0:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/DecreaseSaturation.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$FF&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDDecreaseSaturation0&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
No necesitas repetir la selección en &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; mientras quieras mantener el mismo efecto. Dynamic Xtreme procesa los colores de las paletas habilitadas.&lt;br /&gt;
&lt;br /&gt;
Para quitar el efecto, escribe 0 en el ID global y deja que el sistema procese las paletas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Incluir el color fijo o el color 0,0 ===&lt;br /&gt;
&lt;br /&gt;
Estos dos colores se controlan mediante &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt;. El bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; permite el efecto en el color fijo y &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; en el color 0,0. Para habilitar ambos, utiliza &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para incluir el color fijo sin cambiar la opción del color 0,0:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    LDA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
    ORA #$01&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hacer que el efecto se repita en un ciclo ===&lt;br /&gt;
&lt;br /&gt;
Para animar un efecto, prepara varios efectos consecutivos dentro del mismo archivo y ve cambiando el ID seleccionado. Este ejemplo utiliza cuatro tonos HSL con el cambio aplicado al máximo. Guarda el archivo como &amp;lt;code&amp;gt;DynamicXtreme/Hue.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0,  &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 8,  &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 16, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 24, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, los defines &amp;lt;code&amp;gt;!PaletteEffectIDHue0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDHue3&amp;lt;/code&amp;gt; quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre procede del archivo y utiliza la normalización habitual en PascalCase.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Hue.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$FF&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDHue0&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $9D&lt;br /&gt;
    ORA $13D4|!addr&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$07&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!PaletteEffectIDHue3&lt;br /&gt;
    BCS .Restart&lt;br /&gt;
    INC A&lt;br /&gt;
    BRA .Store&lt;br /&gt;
.Restart&lt;br /&gt;
    LDA #!PaletteEffectIDHue0&lt;br /&gt;
.Store&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El código mantiene cada efecto durante ocho frames y vuelve al primero después de mostrar el último. Puedes añadir más pasos al archivo y cambiar el define del último efecto para obtener una animación más suave.&lt;br /&gt;
&lt;br /&gt;
=== Hacer una transición que se detiene al terminar ===&lt;br /&gt;
&lt;br /&gt;
Para cambiar poco a poco los colores y conservar el resultado final, utiliza una secuencia como esta. El ejemplo reduce el rojo y el verde para dar un aspecto azulado al nivel. Guarda el archivo como &amp;lt;code&amp;gt;DynamicXtreme/Night.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 0,   &amp;quot;Ratio2&amp;quot;: 0,   &amp;quot;EffectType&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 42,  &amp;quot;Ratio2&amp;quot;: 42,  &amp;quot;EffectType&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 85,  &amp;quot;Ratio2&amp;quot;: 85,  &amp;quot;EffectType&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 2 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Selecciona &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;, con las máscaras de paleta del ejemplo anterior. Para avanzar y detenerte al llegar al último, utiliza este &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Night.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $9D&lt;br /&gt;
    ORA $13D4|!addr&lt;br /&gt;
    BNE .Return&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$07&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!PaletteEffectIDNight3&lt;br /&gt;
    BCS .Done&lt;br /&gt;
    INC A&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
.Done&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDNight3&amp;lt;/code&amp;gt; se generan desde &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres siguen la normalización en PascalCase. Este código avanza por los efectos de mezcla del archivo; para una transición hacia otra paleta completa, utiliza un efecto &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt;, explicado en [[es/Dynamic_Xtreme_files_and_formats#Transiciones_de_paleta|Archivos y formatos]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_ASM_API&amp;diff=21358</id>
		<title>es/Dynamic Xtreme ASM API</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_ASM_API&amp;diff=21358"/>
		<updated>2026-10-24T22:39:07Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_ASM_API}}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Para aprender a organizar un sprite completo, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites]].&lt;br /&gt;
&lt;br /&gt;
== Variables y defines ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Los nombres de variables generales comienzan con &amp;lt;code&amp;gt;DX_&amp;lt;/code&amp;gt; y se escriben sin &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt;, por ejemplo &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;. Los defines como &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; sí llevan &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt;. Conserva la escritura exacta del nombre que aparece en el archivo.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Variables generales ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Contadores y cantidad de datos por frame ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; || 2 bytes || Cantidad de bytes que ya se programaron para transferir durante el frame actual. La actualizan las rutinas de carga.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; || 2 bytes || Límite de bytes que las cargas normales pueden programar en un frame. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; pueden superarlo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Poses cargadas en VRAM ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 byte || Cantidad de poses registradas actualmente en la caché.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 valores de 1 byte || Ayuda a encontrar las poses por su ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 128 valores de 2 bytes || ID de cada pose registrada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 128 valores de 2 bytes || Valor de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; de la última vez que se utilizó cada pose. Evita reemplazar gráficos que todavía se están mostrando.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 bytes compartidos || Describen las partes libres u ocupadas de VRAM. Son dos nombres para el mismo espacio de memoria.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 valores de 1 byte || Ayuda al sistema a recorrer las partes libres y ocupadas de VRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Paletas y efecto global ====&lt;br /&gt;
&lt;br /&gt;
Las tablas de 16 paletas utilizan el orden 0-F. En las tablas de valores de 2 bytes, la paleta 1 comienza en &amp;lt;code&amp;gt;+2&amp;lt;/code&amp;gt;, la 2 en &amp;lt;code&amp;gt;+4&amp;lt;/code&amp;gt;, y así sucesivamente.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 byte || Cada bit indica si una de las paletas 0-7 recibe el efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 byte || Cada bit indica si una de las paletas de sprites 8-F recibe el efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || ID del efecto global que se quiere aplicar. El valor 0 indica que no se aplica un efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Último efecto global revisado por el sistema. Se utiliza para detectar cambios.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 16 valores de 2 bytes || Último efecto global calculado para cada paleta. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; significa que aún no hay un resultado; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt;, que hay una actualización pendiente y se conserva el resultado anterior.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 16 valores de 2 bytes || ID asociado a cada paleta. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica que está libre; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; la excluye de la selección automática.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_Updated&amp;lt;/code&amp;gt; || 16 valores de 1 byte || Indica cuáles paletas ya se actualizaron durante el frame. Uso interno.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 byte || Registra qué paletas de sprites se utilizan con efectos. Uso interno del manejo de paletas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para reservar una paleta de sprites y evitar que la selección automática la utilice, su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; debe contener &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt;. Haz la reserva antes de que los sprites comiencen a solicitar paletas.&lt;br /&gt;
&lt;br /&gt;
==== Copias de colores y resultados de efectos ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 bytes || Copia de trabajo de las 256 entradas de color, con 2 bytes por color. Es la fuente de las variantes &amp;lt;code&amp;gt;SetRGBBaseDefault&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SetHSLBaseDefault&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 bytes || Colores originales separados en rojo, verde y azul: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 bytes || Colores originales separados en tono, saturación y luminosidad: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LocalEffectBuffer&amp;lt;/code&amp;gt; || 768 bytes || Espacio de trabajo para el resultado de un efecto local antes de combinarlo con el global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LocalEffectID&amp;lt;/code&amp;gt; || 16 valores de 2 bytes || ID del efecto local aplicado a cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 bytes || Colores resultantes en formato de SNES, con 2 bytes por color. Las variantes &amp;lt;code&amp;gt;AndMergeDefault&amp;lt;/code&amp;gt; escriben aquí.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Cada bit indica si ya se preparó la base RGB de una paleta de fondo o de sprites.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Lo mismo para las bases HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Cada bit indica si ya hay un resultado del efecto para esa paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LastPlayerPal&amp;lt;/code&amp;gt; || 2 bytes || Dirección de la última paleta del jugador procesada. El sistema la compara para detectar cambios.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Color fijo y primer color de la paleta ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 byte || Activa la participación en el efecto global: bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; para el color fijo y bit &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; para el color 0,0. &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; permite ambos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_BaseLoaded&amp;lt;/code&amp;gt; || 1 byte || Indica si se guardaron sus colores originales. Utiliza un bit por destino: &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_RGBBaseLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_ColorEffect_HSLBaseLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Indican si sus colores ya se prepararon en RGB o HSL, con los mismos bits.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Mirror&amp;lt;/code&amp;gt; || 2 bytes || Copia del color fijo que utiliza la actualización habitual del juego.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Base&amp;lt;/code&amp;gt; || 2 bytes || Color fijo original, antes de los efectos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_RGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_FixedColor_HSLBase&amp;lt;/code&amp;gt; || 3 bytes cada una || Color fijo original separado en RGB o HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Result&amp;lt;/code&amp;gt; || 2 bytes || Color fijo calculado después del efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Último efecto global calculado para el color fijo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Base&amp;lt;/code&amp;gt; || 2 bytes || Color 0,0 original.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_RGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_HSLBase&amp;lt;/code&amp;gt; || 3 bytes cada una || Color 0,0 original separado en RGB o HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Result&amp;lt;/code&amp;gt; || 2 bytes || Color 0,0 que se quiere mostrar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Último efecto global calculado para el color 0,0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Update&amp;lt;/code&amp;gt; || 1 byte || Un valor distinto de 0 solicita copiar &amp;lt;code&amp;gt;Result&amp;lt;/code&amp;gt; al color 0,0 durante NMI. Después de copiarlo, el sistema vuelve a poner esta variable en 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Transferencias pendientes ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || Cantidad de copias de gráficos pendientes, en 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || Cantidad de bytes de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || Destino de cada copia en VRAM, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || Dirección de origen de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || Banco de origen de cada copia. La tabla reserva 2 bytes por entrada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || Cantidad de copias de colores pendientes, en 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || Cantidad de bytes de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || Primer color de destino de cada copia, en valores de 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || Dirección de origen de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || Banco de origen de cada copia.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Jugador y Yoshi ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_Enable&amp;lt;/code&amp;gt; || 1 byte || 0 desactiva la carga de gráficos mediante este sistema; un valor distinto de 0 la activa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_Addr&amp;lt;/code&amp;gt; || 2 bytes || Dirección de inicio de los gráficos del jugador dentro del banco indicado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_BNK&amp;lt;/code&amp;gt; || 2 bytes reservados || Banco de origen de los gráficos del jugador. El banco se indica en el byte bajo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_Enable&amp;lt;/code&amp;gt; || 1 byte || 0 desactiva el manejo de paleta del jugador mediante este sistema; un valor distinto de 0 lo activa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_Addr&amp;lt;/code&amp;gt; || 2 bytes || Dirección de origen de la paleta del jugador.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_BNK&amp;lt;/code&amp;gt; || 1 byte || Banco de la paleta. Cuando es 0, la rutina toma la dirección de paleta que utiliza el juego.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_CustomPlayer&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_Dynamic_Player_LastCustomPlayer&amp;lt;/code&amp;gt; || 1 byte cada una || Variables reservadas para identificar al jugador personalizado y el anterior. La inicialización las pone en 0 y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;; actualmente no seleccionan por sí solas los gráficos de un personaje.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_VRAMEnable&amp;lt;/code&amp;gt; || 1 byte || 0 desactiva la carga de gráficos de Yoshi mediante este sistema; un valor distinto de 0 la activa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_Addr&amp;lt;/code&amp;gt; || 2 bytes || Dirección de inicio de los gráficos de Yoshi dentro de su banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_BNK&amp;lt;/code&amp;gt; || 1 byte || Banco de origen de los gráficos de Yoshi.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Dibujo y variables de sprites ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Drawing_InitialIndexHighPriority&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_Drawing_InitialIndexLowPriority&amp;lt;/code&amp;gt; ocupan 1 byte cada una y llevan la cuenta de las posiciones disponibles para dibujar sprites de prioridad alta o baja. &amp;lt;code&amp;gt;DX_Drawing_OAMMap&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Las variables individuales de sprites se definen en &amp;lt;code&amp;gt;DynamicXSpritesTables.asm&amp;lt;/code&amp;gt;. Los archivos &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; permiten utilizar los mismos nombres para los tres tipos:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Nombre para el sprite !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt; || Pose que se quiere mostrar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt; || Última pose que se consiguió y puede dibujarse. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; || Entrada donde el sistema tiene registrada la ubicación de sus gráficos. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt; || Volteo general, volteo adicional de la pose y volteo que se utiliza para dibujar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; || Paleta asignada: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; para la 8, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; para la 9, y así hasta &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; para la F. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; cuando se utiliza asignación dinámica.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; || Opciones &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: efecto global y elección de paleta o grupo de paletas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; || Modo de asignación: automático, manual o manual sin cargar colores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt; || Variante del sprite y última variante procesada al manejar su paleta. &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt; se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen,x&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SafeFrameLowByte,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!SafeFrameHighByte,x&amp;lt;/code&amp;gt; || Último frame en que se intentó solicitar una pose, para evitar repetir el trabajo durante el mismo frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AnimationIndex,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AnimationPoseIndex,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AnimationTimer,x&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!State,x&amp;lt;/code&amp;gt; || Variable para el estado o comportamiento del recurso.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada variable de esta tabla ocupa 1 byte por sprite. Hay &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; entradas para normales, 20 para cluster y 10 para extended. No utilices &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; como cantidad de entradas de cluster o extended.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Defines fijos ===&lt;br /&gt;
&lt;br /&gt;
Estos nombres representan configuraciones y direcciones conocidas. No son variables que cambian durante el juego.&lt;br /&gt;
&lt;br /&gt;
==== Compatibilidad con LoROM y SA-1 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; detecta el tipo de ROM y elige los valores correspondientes. Utiliza estos nombres para que tu código funcione en ambos casos.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! LoROM !! SA-1 !! Uso&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!sa1&amp;lt;/code&amp;gt; || 0 || 1 || Permite elegir código distinto según el tipo de ROM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!dp&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3000&amp;lt;/code&amp;gt; || Ajuste de las direcciones de página directa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!addr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; || Ajuste de las direcciones RAM que lo requieren, por ejemplo &amp;lt;code&amp;gt;$0100|!addr&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!rom&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$800000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$000000&amp;lt;/code&amp;gt; || Ajuste utilizado al acceder a direcciones del código original del juego.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; (12) || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; (22) || Cantidad de posiciones de sprites normales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MultiplicationResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4216&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2306&amp;lt;/code&amp;gt; || Dirección donde se lee el resultado de una multiplicación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DivisionResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4214&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2306&amp;lt;/code&amp;gt; || Dirección donde se lee el cociente de una división.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RemainderResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4216&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2308&amp;lt;/code&amp;gt; || Dirección donde se lee el resto de una división.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Otros defines utilizados para colocar las variables son &amp;lt;code&amp;gt;!normalBnk&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalCopyBNK&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt;. Normalmente basta con utilizar el nombre de cada variable &amp;lt;code&amp;gt;DX_...&amp;lt;/code&amp;gt;, sin calcular su dirección a partir de estos valores.&lt;br /&gt;
&lt;br /&gt;
==== Direcciones de gráficos en VRAM ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia !! Línea 0 !! Avance por línea !! Ejemplo&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG1LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG1Line1 = $0100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG2LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG2Line1 = $0900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG1LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG1Line1 = $1100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG3LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG3Line1 = $1900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG2LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG2Line1 = $2100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG3LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG3Line1 = $2900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LG1LineN&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!LG4LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4400&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4800&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4C00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!LG1Line1 = $4080&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SP1LineN&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!SP4LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6800&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$7000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$7800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!SP4Line1 = $7900&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Layer1Tilemap = $3000&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Layer2Tilemap = $3800&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
==== Configuraciones de espacio para poses dinámicas ====&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt; se entregan a &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt;. El nombre indica qué áreas de gráficos se permiten utilizar. &amp;lt;code&amp;gt;FirstHalf&amp;lt;/code&amp;gt; significa primera mitad y &amp;lt;code&amp;gt;SecondHalf&amp;lt;/code&amp;gt;, segunda mitad. Los nombres con &amp;lt;code&amp;gt;WithPlayer&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;WithDSX&amp;lt;/code&amp;gt; corresponden a las configuraciones previstas para esos casos.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Define&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$09&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP1WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP11WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3ndSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2andSP34&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$11&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$13&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$15&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3ndSP4WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$17&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2andSP34WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$19&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithPlayerAndDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithPlayerAndDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres de esta tabla se escriben exactamente como aparecen en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, incluidos nombres como &amp;lt;code&amp;gt;SecondHalfSSP4&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SP11WithPlayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Otras constantes ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! Valor o uso&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AN2Buffer1&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AN2Buffer2&amp;lt;/code&amp;gt; || Direcciones &amp;lt;code&amp;gt;$7EC100&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$7EAD00&amp;lt;/code&amp;gt; utilizadas para datos de animación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt;, dirección del buffer habitual de GFX32.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PlayerPaletteColor2To5&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$00B280&amp;lt;/code&amp;gt;, datos de los colores 2-5 de la paleta del jugador.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PlayerBasePalette&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$00B2C8&amp;lt;/code&amp;gt;, datos de la paleta base del jugador.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las opciones de instalación, como &amp;lt;code&amp;gt;!DynamicPoses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DrawingSystem&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!GraphicsChange&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalettesChange&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalettesEffects&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PlayerFeatures&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!YoshiFeatures&amp;lt;/code&amp;gt;, se incluyen desde &amp;lt;code&amp;gt;Options.asm&amp;lt;/code&amp;gt;. Sus valores indican qué funciones se instalaron; no se cambian durante el juego.&lt;br /&gt;
&lt;br /&gt;
=== Defines generados ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme crea estos defines al instalar los recursos y los añade a &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
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, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;my-sprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;my sprite&amp;lt;/code&amp;gt; se convierten en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. 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 &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Poses dinámicas y poses de dibujo ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia o ejemplo !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; || ID de unos gráficos de pose declarados en el DynamicInfo. Se utiliza para solicitar su carga con &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseMySprite000&amp;lt;/code&amp;gt; || Dirección ROM de esos gráficos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseMySprite000Size&amp;lt;/code&amp;gt; || Tamaño de esos gráficos en bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; || ID de una pose del DrawInfo. Se utiliza para dibujarla con &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;DrawStatic&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; || Distancia horizontal calculada desde el DrawInfo para saber cuándo el sprite deja de verse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; || Distancia vertical calculada desde el DrawInfo para la misma comprobación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; no se utiliza en lugar de un &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Paletas y efectos ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia o ejemplo !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteIDMyPalette&amp;lt;/code&amp;gt; || ID de una paleta declarada desde el DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; || Dirección ROM de sus colores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyPaletteSize&amp;lt;/code&amp;gt; || Tamaño de la paleta en bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; || Indica dónde comienza la lista de paletas de ese DynamicInfo. Se entrega a &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; y a sus variantes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; || ID de un efecto de &amp;lt;code&amp;gt;my_effect.paleffect&amp;lt;/code&amp;gt;. El número final identifica el efecto dentro del archivo; los IDs globales comienzan en 1.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyTargetRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PaletteMyTargetHSL&amp;lt;/code&amp;gt; || Dirección ROM de una paleta de destino convertida para una transición RGB o HSL. Se genera cuando un efecto necesita esa paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyTargetRGBSize&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PaletteMyTargetHSLSize&amp;lt;/code&amp;gt; || Tamaño en bytes de esas paletas convertidas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres de los ejemplos usan la misma normalización: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. Los defines se generan durante la instalación y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y buffers ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia o ejemplo !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt; || ID de un recurso general del DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt; || Dirección ROM de ese recurso.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt; || Tamaño del recurso en bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferIDMyBuffer&amp;lt;/code&amp;gt; || ID de un buffer insertado por la herramienta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferMyBuffer&amp;lt;/code&amp;gt; || Dirección del buffer insertado en la ROM; no es una variable temporal de RAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferMyBufferSize&amp;lt;/code&amp;gt; || Tamaño del buffer en bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres dependen de los recursos instalados. Se normalizan del mismo modo: &amp;lt;code&amp;gt;my_resource&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyResource&amp;lt;/code&amp;gt;. Consulta &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; para ver los nombres y valores de tu instalación.&lt;br /&gt;
&lt;br /&gt;
==== Cantidades y tablas generadas ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfDynamicPoses&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfPoses&amp;lt;/code&amp;gt; || Cantidad de poses dinámicas y de poses de dibujo instaladas, respectivamente.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfPalettes&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfResources&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfBuffers&amp;lt;/code&amp;gt; || Cantidad de paletas normales, recursos generales y buffers insertados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfPaletteEffects&amp;lt;/code&amp;gt; || 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 &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteTableSize&amp;lt;/code&amp;gt; || Cantidad total de entradas en las listas de paletas de los DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteIDTables&amp;lt;/code&amp;gt; || Dirección de la tabla de IDs de esas listas de paletas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAddrTables&amp;lt;/code&amp;gt; || Dirección de la tabla con las direcciones ROM de sus colores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsTypes&amp;lt;/code&amp;gt; || Tabla con el tipo de cada efecto instalado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsChannels1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsChannels2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsChannels3&amp;lt;/code&amp;gt; || Tablas con los valores de color de cada efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsRatios1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsRatios2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsRatios3&amp;lt;/code&amp;gt; || Tablas con los ratios que controlan cuánto se aplica cada cambio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferTable&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteTables&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsTable&amp;lt;/code&amp;gt; || Direcciones de las tablas que el parche publica para esos datos.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Defines de rutinas ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define o familia !! Uso&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AllowedGameMode&amp;lt;/code&amp;gt; || Comprueba si el modo de juego actual permite procesar las operaciones correspondientes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; || Elige las partes de VRAM disponibles para poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; || Solicita una pose por su ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; || Prepara las copias de gráficos de una pose a VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SetPropertyAndOffset&amp;lt;/code&amp;gt; || Obtiene la ubicación y propiedades de los gráficos de una pose dinámica para dibujarla.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Draw&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!Draw_Return&amp;lt;/code&amp;gt; || Entrada y punto de retorno utilizados por las rutinas de dibujo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RemapOamTile&amp;lt;/code&amp;gt; || Ajusta el número de tile para utilizar la ubicación real de los gráficos dinámicos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!IsValid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!XIsValid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!YIsValid&amp;lt;/code&amp;gt; || Comprobaciones utilizadas por el dibujo para decidir si un tile puede mostrarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AssignPalette&amp;lt;/code&amp;gt; || Selecciona el destino de una paleta según el modo de asignación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LoadPaletteOnBuffer&amp;lt;/code&amp;gt; || Carga datos de paleta en un espacio de trabajo para procesarlos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SetRGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!SetHSLBase&amp;lt;/code&amp;gt; || Prepara los colores para calcular efectos RGB o HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RGBToHSL&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!HSLToRGB&amp;lt;/code&amp;gt; || Convierte entre ambos sistemas de color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RGBMerge&amp;lt;/code&amp;gt; || Convierte colores RGB separados al formato de paleta de SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Mix...&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!MixAndMerge...&amp;lt;/code&amp;gt; || Aplica cambios a uno o varios componentes del color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalTransitionRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PalTransitionHSL&amp;lt;/code&amp;gt; || Calcula el cambio de una paleta a otra.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalTransitionAndMergeRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PalTransitionAndMergeHSL&amp;lt;/code&amp;gt; || Calcula la transición y deja el resultado en formato de SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DoEffect&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!DoEffectAndMerge&amp;lt;/code&amp;gt; || Aplica un efecto mediante su ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalFunctionRGB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalFunctionHSL&amp;lt;/code&amp;gt; y variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Nombres reservados para funciones de color que todavía no están implementadas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Routines&amp;lt;/code&amp;gt; es la dirección de la tabla desde la que se obtienen estas llamadas. No necesitas calcular sus posiciones para usar los defines publicados.&lt;br /&gt;
&lt;br /&gt;
== Rutinas para sprites ==&lt;br /&gt;
&lt;br /&gt;
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: &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt;. La ruta del include es relativa al archivo ASM del sprite.&lt;br /&gt;
&lt;br /&gt;
Para usar llamadas como &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, escribe su nombre directamente, como muestran los ejemplos. No añadas &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt; delante. Salvo que se indique lo contrario, X debe contener el número del slot que ocupa el sprite.&lt;br /&gt;
&lt;br /&gt;
=== RenderBox ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; 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).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen,x&amp;lt;/code&amp;gt;: distancias horizontal y vertical permitidas fuera de la pantalla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite está en pantalla o dentro de la distancia permitida fuera de sus bordes; se debe ejecutar la long routine.&lt;br /&gt;
* Carry desactivado: el sprite está demasiado lejos de la pantalla para dibujarse; se debe ejecutar la short routine.&lt;br /&gt;
&lt;br /&gt;
Cuando el sprite está demasiado lejos, establece &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Esto indica que deberá volver a obtener su paleta y su pose cuando se acerque a la pantalla. También guarda en &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt; el volteo que resulta de combinar &amp;lt;code&amp;gt;!GlobalFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip&amp;lt;/code&amp;gt;. En sprites normales actualiza además las variables que indican si está fuera de pantalla horizontal o verticalmente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
print &amp;quot;INIT &amp;quot;,pc&lt;br /&gt;
    LDA.b #!RenderBoxXDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderXDistanceOutOfScreen,x&lt;br /&gt;
    LDA.b #!RenderBoxYDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderYDistanceOutOfScreen,x&lt;br /&gt;
    ; Aquí va el resto de la inicialización del sprite&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
SpriteCode:&lt;br /&gt;
    !RenderBox&lt;br /&gt;
    BCS .LongRoutine&lt;br /&gt;
&lt;br /&gt;
.ShortRoutine&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    %SubOffScreen()&lt;br /&gt;
    ; Aquí va la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&lt;br /&gt;
.LongRoutine&lt;br /&gt;
    ; Aquí van el manejo de paletas, poses y dibujo&lt;br /&gt;
    ; y la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La llamada a &amp;lt;code&amp;gt;%SubOffScreen()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; se generan desde el DrawInfo y se guardan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. 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, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Si el sprite utiliza varios DrawInfo, utiliza la mayor distancia horizontal y la mayor distancia vertical entre ellos.&lt;br /&gt;
&lt;br /&gt;
=== PaletteAssignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; selecciona una paleta del DynamicInfo usando &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
Si el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; está activado (&amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;), también procesa los efectos globales de paleta correspondientes. Si está desactivado, la paleta queda excluida del efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cómo se elige la paleta&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; indica qué paleta de sprites se permite utilizar y si sus colores reciben el efecto global. Su formato es &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt;: 0 excluye la paleta del efecto global; 1 permite aplicarlo.&lt;br /&gt;
* &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt;: con asignación manual, selecciona una paleta entre 8 y F. &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; elige la 8, &amp;lt;code&amp;gt;001&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* Con asignación automática, &amp;lt;code&amp;gt;PPP = 000&amp;lt;/code&amp;gt; permite buscar entre las ocho paletas. Un valor &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; limita la búsqueda a las paletas 8-B; un valor &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; la limita a las C-F.&lt;br /&gt;
* Los cuatro bits bajos no se utilizan para estas opciones.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; decide quién elige el destino y si se cargan colores. Su formato es &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 00&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;): automático. Dynamic Xtreme elige una de las paletas permitidas y carga los colores del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 01&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;): manual. Utiliza la paleta indicada en &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; y carga los colores del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 10&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;): manual sin carga. Utiliza la paleta indicada en &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; con los colores que ya tiene el nivel.&lt;br /&gt;
&lt;br /&gt;
En sprites normales, &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; es &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; es &amp;lt;code&amp;gt;!ExtraProp2,x&amp;lt;/code&amp;gt;. Lo habitual es usar el primer Extra Byte con formato &amp;lt;code&amp;gt;EPPPVVVV&amp;lt;/code&amp;gt; y copiar sus cuatro bits bajos a &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, con asignación manual, &amp;lt;code&amp;gt;!PaletteOption,x = $A0&amp;lt;/code&amp;gt; utiliza la paleta A y permite el efecto global. Si &amp;lt;code&amp;gt;!Version,x = 1&amp;lt;/code&amp;gt;, carga en ella la segunda paleta de la lista del DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; correspondiente al DynamicInfo que contiene las paletas.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;: índice de la paleta dentro de la tabla.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: última versión procesada. Se compara con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; para detectar cambios y debe inicializarse en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;: selección de paleta y participación en el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt;: asignación automática, manual o manual sin carga.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite puede dibujarse con la paleta asignada.&lt;br /&gt;
* Carry desactivado: el sprite todavía no tiene una paleta lista para dibujar.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta asignada, con valores de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos para las paletas 8-F.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: se actualiza con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; cuando se procesa la nueva asignación.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignment&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre del recurso se normaliza en PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== PaletteAssignmentNoUpload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; elige la paleta igual que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
El bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;) 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 &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; elige la paleta del DynamicInfo: 0 para la primera, 1 para la segunda, etc. &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: 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, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; elige el destino automáticamente, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; usa el indicado en PPP y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt;: mismas opciones que en &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: última versión procesada, utilizada para detectar cambios respecto de &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;. Debe inicializarse en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite tiene una paleta asignada; desactivado si no pudo obtenerse.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta asignada.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: se actualiza con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; cuando se procesa la nueva asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: número que identifica la paleta elegida del DynamicInfo, cuando se utiliza un modo que carga sus colores.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base en ROM.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    ; Aquí se prepara y concatena el efecto.&lt;br /&gt;
    ; Conserva Y y la dirección de $02-$04 para esa llamada.&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; dice qué paleta del DynamicInfo se eligió; &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; dice cuál de las paletas 8-F utilizará el sprite para dibujarse. Los datos de &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;, eliminando los separadores.&lt;br /&gt;
&lt;br /&gt;
=== Upload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; consigue los gráficos de la pose que el sprite quiere mostrar. La pose se selecciona sumando &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico base.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt;: índice que se suma al ID base.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt;: volteos que se combinarán para dibujar.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* Carry desactivado: el sprite todavía no tiene una pose disponible.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt;: estado de la pose disponible para dibujar.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    !Upload&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== UploadWithoutPoseOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; solicita directamente el ID dinámico entregado en A, sin sumarle &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;. Como &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, reutiliza los gráficos si ya están en VRAM y puede seguir mostrando la pose anterior mientras no consiga cargar la nueva.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: existe &amp;lt;code&amp;gt;%DXExtendedUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;, pero actualmente &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; no publica el alias &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico exacto.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt;: volteos del sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite tiene una pose disponible para dibujar; desactivado si todavía no tiene ninguna.&lt;br /&gt;
* Guarda la pose que se puede dibujar en &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt; y la ubicación de sus gráficos en &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;, igual que &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite003&lt;br /&gt;
    !UploadWithoutPoseOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite003&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== DXDraw ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; dibuja una pose utilizando los gráficos dinámicos disponibles para el sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID de la pose de dibujo.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;): propiedades adicionales, con formato &amp;lt;code&amp;gt;YXCC----&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;): prioridad máxima de los tiles; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; máxima, &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; alta, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; propia del tipo de sprite y &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; mínima.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;: paleta, volteo y ubicación de los gráficos disponibles.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose en pantalla. Si &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no dibuja. A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDraw&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, las poses deben estar en el mismo orden en el DrawInfo y el DynamicInfo. Se utiliza &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; porque indica qué pose se puede dibujar: si la nueva todavía no se pudo cargar, seguirá mostrando la anterior.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres de recurso y pose se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Este ID de dibujo es distinto de los IDs &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; del DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
=== DXDrawWithOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Las mismas entradas de &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;): desplazamiento horizontal de 8 bits con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;): desplazamiento vertical de 8 bits con signo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja igual que &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;, pero suma los desplazamientos que preparaste. Un valor positivo en &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; mueve el dibujo a la derecha; en &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt;, hacia abajo. Los valores negativos lo mueven a la izquierda o hacia arriba.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$08&lt;br /&gt;
    STA !XOffsetParam&lt;br /&gt;
    LDA #$F8&lt;br /&gt;
    STA !YOffsetParam&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDrawWithOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo desplaza el dibujo 8 píxeles a la derecha y 8 hacia arriba. &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; el nombre se normaliza en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ReplacePalette ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Suele utilizarse después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;: primero se asigna la paleta sin cargar sus colores y después se reemplazan por los que quieres mostrar. Antes de llamar a &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, coloca en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; la dirección de los nuevos colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* A en modo de 8 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de la nueva paleta en BGR555.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta ya asignada.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;: participación en el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta; si los nuevos colores todavía no están listos, se conservan los anteriores.&lt;br /&gt;
* Carry desactivado: la paleta todavía no tiene colores listos para dibujar.&lt;br /&gt;
&lt;br /&gt;
Mantiene el mismo ID de paleta, pero solicita cambiar sus colores. Al marcar que el efecto debe volver a calcularse, utiliza &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; si nunca se habían obtenido colores para dibujar, o &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; si puede seguir mostrando los anteriores mientras prepara los nuevos.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ReplaceSpritePalette:&lt;br /&gt;
    ; Ejecutar cuando se necesite cambiar una paleta ya asignada.&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;8&lt;br /&gt;
    STA $03&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
    !ReplacePalette&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyAlternatePalette&amp;lt;/code&amp;gt; es la dirección de una paleta insertada desde los recursos declarados en un DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_alternate_palette&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyAlternatePalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ConcatenateRGBPaletteEffectToGlobal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, y después aplica el global sobre ese resultado. Llámala después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, que deja preparada la paleta original.&lt;br /&gt;
&lt;br /&gt;
El uso habitual es asignar primero la paleta con &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; y, si el carry está activado, llamar a esta rutina para aplicar los efectos y completar la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID del efecto local RGB.&lt;br /&gt;
* X de 8 bits: copia aquí el valor de &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;LDA !Palette,x&amp;lt;/code&amp;gt; seguido de &amp;lt;code&amp;gt;TAX&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
* Y de 8 bits: conserva el valor que dejó &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;. El valor 1 obliga a calcular de nuevo el efecto; 0 permite reutilizar el resultado anterior si no cambió nada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base BGR555 preparada por la asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;: el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; debe estar activado para combinar con el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta. Si el nuevo efecto todavía no está listo, se sigue mostrando el anterior.&lt;br /&gt;
* Carry desactivado: todavía no hay colores listos para dibujar esa paleta.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyRGBEffect0&lt;br /&gt;
    !ConcatenateRGBPaletteEffectToGlobal&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y &amp;lt;code&amp;gt;!PaletteEffectIDMyRGBEffect0&amp;lt;/code&amp;gt; desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. Ambos quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Si se necesita Y para seleccionar el efecto mediante una tabla, conserva su valor con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; y restáuralo con &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; antes de concatenar.&lt;br /&gt;
&lt;br /&gt;
=== ConcatenateHSLPaletteEffectToGlobal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt; permite que la paleta del sprite tenga un efecto HSL propio, como &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, y siga siendo afectada por el efecto global. Primero aplica el efecto local y después el global. Llámala después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, que deja preparada la paleta original.&lt;br /&gt;
&lt;br /&gt;
El uso habitual es asignar primero la paleta con &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; y, si el carry está activado, llamar a esta rutina para aplicar los efectos y completar la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID del efecto local HSL.&lt;br /&gt;
* X de 8 bits: copia aquí el valor de &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;LDA !Palette,x&amp;lt;/code&amp;gt; seguido de &amp;lt;code&amp;gt;TAX&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
* Y de 8 bits: conserva el valor que dejó &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;. El valor 1 obliga a calcular de nuevo el efecto; 0 permite reutilizar el resultado anterior si no cambió nada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base BGR555 preparada por la asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;: el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; debe estar activado para combinar con el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta. Si el nuevo efecto todavía no está listo, se sigue mostrando el anterior.&lt;br /&gt;
* Carry desactivado: todavía no hay colores listos para dibujar esa paleta.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyHSLEffect0&lt;br /&gt;
    !ConcatenateHSLPaletteEffectToGlobal&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y &amp;lt;code&amp;gt;!PaletteEffectIDMyHSLEffect0&amp;lt;/code&amp;gt; desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. Quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y utilizan nombres normalizados en PascalCase: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra. Conserva Y con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; si lo utilizas temporalmente para seleccionar el efecto.&lt;br /&gt;
&lt;br /&gt;
Ambas variantes de concatenación realizan las conversiones necesarias si el efecto local y el global utilizan espacios de color diferentes. Consulta [[es/Dynamic_Xtreme_files_and_formats#Tipos_de_efectos|Tipos de efectos]] para identificar los efectos RGB y HSL.&lt;br /&gt;
&lt;br /&gt;
== Rutinas y Macros Generales ==&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!NormalPoseIndex,x&amp;lt;/code&amp;gt;, escríbelo entre comillas para que Asar lo lea como un solo argumento. Utiliza &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; al entregar un valor inmediato, como &amp;lt;code&amp;gt;#$04&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Poses dinámicas ===&lt;br /&gt;
&lt;br /&gt;
==== DynamicPoseSpaceConfig ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; elige qué partes de la memoria gráfica (VRAM) puede usar Dynamic Xtreme para cargar poses dinámicas. Normalmente se llama desde el &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; de UberASM al entrar al nivel.&lt;br /&gt;
&lt;br /&gt;
Los defines con las configuraciones disponibles se encuentran en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, bajo los nombres &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 8 bits: una de las configuraciones &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus valores van de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicSpaceConfigSP4&amp;lt;/code&amp;gt; es una constante publicada en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permite utilizar SP4. Otras opciones incluyen &amp;lt;code&amp;gt;!DynamicSpaceConfigSP3&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt;. Selecciona una región que no se superponga con los gráficos estáticos utilizados por el nivel.&lt;br /&gt;
&lt;br /&gt;
==== TakeDynamicRequest ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !TakeDynamicRequest&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Y de 16 bits: ID exacto de la pose dinámica.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RequestPose:&lt;br /&gt;
    REP #$10&lt;br /&gt;
    LDY #!DynamicPoseIDMySprite000&lt;br /&gt;
    JSL !TakeDynamicRequest&lt;br /&gt;
    BCC .Unavailable&lt;br /&gt;
&lt;br /&gt;
    ; X contiene el índice hash de la pose solicitada.&lt;br /&gt;
    ; Aquí tu código puede guardar ese índice para dibujar la pose.&lt;br /&gt;
RTS&lt;br /&gt;
.Unavailable&lt;br /&gt;
    ; Aquí se maneja la falta de recursos.&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores y escribiendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== DynamicRoutine ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !DynamicRoutine&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; prepara esos datos antes de llamarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Datos que necesita la llamada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt;: variable interna de 16 bits que contiene el ID de la pose que se va a copiar.&lt;br /&gt;
* 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.&lt;br /&gt;
&lt;br /&gt;
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. &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; realiza ambas tareas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo de funcionamiento&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Cuando un sprite solicita una pose que todavía no está en VRAM, &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; busca dónde colocarla. Después guarda su ID en &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt; y llama a &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; con la posición elegida en A. Esta última prepara la copia de los gráficos; el NMI ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
Para cargar una pose desde el código de un sprite, utiliza &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. Si necesitas hacer la solicitud directamente mediante su ID, utiliza &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt;. Llamar a &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; requiere preparar también la variable interna del ID, el banco de datos y el espacio de destino descritos arriba.&lt;br /&gt;
&lt;br /&gt;
==== GeneralUpload ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%GeneralUpload(Pose16, checkLast, sprite, flip, safeCheck, withoutOffset,&lt;br /&gt;
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,&lt;br /&gt;
    globalFlip, localFlip, lastFlip)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La firma anterior muestra el orden de los parámetros; escribe la llamada en una sola línea.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Pose16&amp;lt;/code&amp;gt;: 0 utiliza índices de pose de 8 bits; 1 utiliza índices de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt;: 1 permite seguir dibujando la pose anterior si no se pudo obtener la nueva; 0 desactiva esa opción.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 0 para usar variables propias sin recuperar el índice del sprite; 1 para trabajar con las tablas del sprite, recuperando X desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 2 funciona como 1, pero solicita la pose sin comparar ni cambiar &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;flip&amp;lt;/code&amp;gt;: 1 combina &amp;lt;code&amp;gt;globalFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;localFlip&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;; 0 omite esa actualización.&lt;br /&gt;
* &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt;: 1 evita repetir la solicitud en el mismo frame utilizando &amp;lt;code&amp;gt;safeLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;safeHigh&amp;lt;/code&amp;gt;; 0 omite la comprobación.&lt;br /&gt;
* &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;: 0 suma &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt; al ID base; 1 utiliza directamente el ID recibido.&lt;br /&gt;
* &amp;lt;code&amp;gt;safeLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;safeHigh&amp;lt;/code&amp;gt;: variables que guardan los bytes bajo y alto del frame de la solicitud. Se escriben incluso cuando &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; es 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt;: variable del índice de pose deseado.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;: variable del último índice de pose disponible.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;: variable que identifica la entrada donde Dynamic Xtreme guarda la ubicación de los gráficos en VRAM. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; indica que todavía no hay gráficos disponibles.&lt;br /&gt;
* &amp;lt;code&amp;gt;globalFlip&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;localFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variables del volteo global, local y efectivo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada adicional&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico base o exacto, según &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Para &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; debe contener el índice del sprite.&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt;, la macro solicita la pose aunque &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sean iguales, y deja &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sin modificar. Si consigue los gráficos, guarda su ubicación en &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;. Si la solicitud falla y &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; es 1, puede seguir usando los gráficos anteriores. &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; sigue controlando si se permite repetir la solicitud durante el mismo frame.&lt;br /&gt;
&lt;br /&gt;
Este valor 2 no cambia el tamaño de los índices. Para utilizar variables de índice de 16 bits se selecciona &amp;lt;code&amp;gt;Pose16 = 1&amp;lt;/code&amp;gt;. El ID dinámico entregado en A siempre es de 16 bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Devuelve el carry activado cuando hay una pose disponible para dibujar: la solicitada o la anterior si &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; al final; colócala al final de una rutina llamada con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %GeneralUpload(0, 1, 1, 1, 1, 0, &amp;quot;!NormalSafeFrameLowByte,x&amp;quot;, &amp;quot;!NormalSafeFrameHighByte,x&amp;quot;, &amp;quot;!NormalPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalGlobalFlip,x&amp;quot;, &amp;quot;!NormalLocalFlip,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las tablas de un sprite normal y un índice de pose de 8 bits. &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; el nombre se normaliza en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Upload (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%Upload()&amp;lt;/code&amp;gt; es la variante de &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; para índices de pose de 8 bits. No debe confundirse con el alias para sprites &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Upload(sprite, checkLast, flip, safeCheck, withoutOffset,&lt;br /&gt;
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,&lt;br /&gt;
    globalFlip, localFlip, lastFlip)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Recibe los mismos datos que &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt;, pero los índices guardados en las variables siempre son de 8 bits. La macro ya incluye el &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
El parámetro &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt; también admite 2: omite la comparación con &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; y no actualiza esa variable, pero sí actualiza &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt; al obtener la pose. No habilita índices de 16 bits; para eso se utiliza &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;Pose16 = 1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sin modificar, el código del sprite puede controlar ese cambio.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %Upload(1, 1, 1, 1, 0, &amp;quot;!NormalSafeFrameLowByte,x&amp;quot;, &amp;quot;!NormalSafeFrameHighByte,x&amp;quot;, &amp;quot;!NormalPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalGlobalFlip,x&amp;quot;, &amp;quot;!NormalLocalFlip,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; es generado desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpriteUpload ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpriteUpload(withoutOffset, type)&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;: 0 suma &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; al ID base; 1 utiliza el ID exacto.&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A de 16 bits: ID dinámico.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* Tablas de poses y volteo de Dynamic Xtreme del tipo seleccionado, inicializadas como en las rutinas &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %StandardSpriteUpload(0, &amp;quot;Normal&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;, eliminando los separadores.&lt;br /&gt;
&lt;br /&gt;
=== Dibujo de poses ===&lt;br /&gt;
&lt;br /&gt;
Las macros de esta categoría terminan la rutina que las contiene mediante &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;. Los ejemplos deben llamarse con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;. A debe contener el ID de dibujo con 16 bits; &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;) se preparan igual que para &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Draw ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%Draw()&amp;lt;/code&amp;gt; dibuja una pose dinámica. En la llamada indicas qué gráficos usar, su paleta, su volteo y la posición donde quieres dibujarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Draw(offset, sprite, lastPoseHashIndex, lastFlip, palette, xl, xh, yl, yh)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 utiliza las coordenadas entregadas; 1 añade &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;), de 8 bits con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 recupera el índice del sprite en X desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; antes de leer su paleta y posición; 0 omite ese paso.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;: variable que identifica dónde están registrados los gráficos de la pose en Dynamic Xtreme. Si contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no se dibuja.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variable o valor que indica el volteo con el que se dibujará.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de la paleta; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; selecciona la 8, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* &amp;lt;code&amp;gt;xl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;xh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición X.&lt;br /&gt;
* &amp;lt;code&amp;gt;yl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;yh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose con los gráficos indicados por &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMySprite_Frame0&lt;br /&gt;
    %Draw(0, 1, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. El ID debe corresponder a los gráficos dinámicos disponibles.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpriteDraw ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpriteDraw(offset, type)&amp;lt;/code&amp;gt; dibuja una pose dinámica utilizando las tablas de Dynamic Xtreme del tipo de sprite seleccionado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 sin desplazamiento adicional; 1 utiliza los offsets de &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A de 16 bits: ID de dibujo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt;: propiedades y prioridad.&lt;br /&gt;
* Las tablas de paleta, último volteo e índice hash de Dynamic Xtreme del tipo seleccionado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;%Draw()&amp;lt;/code&amp;gt;, utilizando las tablas estándar. Es la macro que utilizan las rutinas PIXI &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para sprites normales, las rutinas PIXI preparan los aliases de coordenadas &amp;lt;code&amp;gt;!NormalXLow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!NormalXHigh&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!NormalYLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!NormalYHigh&amp;lt;/code&amp;gt;. Si se expande la macro directamente, también deben estar definidos, como en este ejemplo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!NormalXLow = !SpriteXLow&lt;br /&gt;
!NormalXHigh = !SpriteXHigh&lt;br /&gt;
!NormalYLow = !SpriteYLow&lt;br /&gt;
!NormalYHigh = !SpriteYHigh&lt;br /&gt;
&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMySprite_Frame0&lt;br /&gt;
    %StandardSpriteDraw(0, &amp;quot;Normal&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== DrawStatic ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt; dibuja una pose estática, declarada con &amp;lt;code&amp;gt;.IsStatic&amp;lt;/code&amp;gt; en el DrawInfo. Sus gráficos deben estar previamente cargados en las posiciones de VRAM indicadas por sus tiles.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%DrawStatic(offset, sprite, lastFlip, palette, xl, xh, yl, yh)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 sin desplazamiento adicional; 1 utiliza &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;), con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: parámetro conservado en la firma; la implementación actual de esta macro no lo utiliza.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variable o valor que indica el volteo; &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; dibuja sin volteo.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de paleta: &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; selecciona la 8, &amp;lt;code&amp;gt;#$02&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;#$0E&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* &amp;lt;code&amp;gt;xl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;xh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición X.&lt;br /&gt;
* &amp;lt;code&amp;gt;yl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;yh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas adicionales&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID de dibujo estático.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;): propiedades y prioridad.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;): 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose sin consultar la caché de gráficos dinámicos. No requiere &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; ni una llamada previa a &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$80&lt;br /&gt;
    STA !Tile&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMyStaticSprite_Frame0&lt;br /&gt;
    %DrawStatic(0, 1, #$00, #$04, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza el tile &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; si la pose está configurada para tomarlo desde &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, sin volteo y con la paleta A. &amp;lt;code&amp;gt;!PoseIDMyStaticSprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_static_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyStaticSprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Paletas ===&lt;br /&gt;
&lt;br /&gt;
Estas macros permiten elegir qué paleta usa un sprite, cargar sus colores y cambiarlos durante el juego.&lt;br /&gt;
&lt;br /&gt;
==== LoadPaletteIDAndAddress ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%LoadPaletteIDAndAddress()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 8 bits: índice de la paleta dentro del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt;: guarda aquí el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; de tu DynamicInfo, con 16 bits, como muestra el ejemplo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: ID de la paleta.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de sus colores en ROM, en formato BGR555.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    STA $0E&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    LDA #$01            ; Segunda paleta del DynamicInfo&lt;br /&gt;
    %LoadPaletteIDAndAddress()&lt;br /&gt;
    ; $00-$01 contiene su ID y $02-$04 su dirección ROM.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En PIXI también puede llamarse mediante &amp;lt;code&amp;gt;%DXLoadPaletteIDAndAddress()&amp;lt;/code&amp;gt;, con las mismas entradas y resultados. Esta variante llama a una rutina compartida y después continúa con el código siguiente.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones bajos y guiones, y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignment (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt; asigna y carga una paleta igual que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
Si la paleta ya estaba asignada, mantiene su temporizador de uso en 2 para que no sea reemplazada mientras se utiliza. Si el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; de las opciones está activado, también aplica el efecto global correspondiente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteAssignment(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 utiliza &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; para acceder a las tablas del sprite; 0 permite usar variables independientes del índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable que recibe la paleta asignada. Debe comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Los valores &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, ..., &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; corresponden a las paletas 8-F.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteAssignment&amp;lt;/code&amp;gt;: variable o valor con formato &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; permite que Dynamic Xtreme elija el destino y cargue los colores; &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; utiliza el destino que tú indicas y carga los colores; &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; utiliza ese destino con los colores que ya tiene el nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor con formato &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;. E = 1 permite aplicar el efecto global; E = 0 lo excluye. En modo manual, PPP elige entre la paleta 8 (&amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt;) y la F (&amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt;). En automático, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F. Los cuatro bits bajos no se usan para estas opciones.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteVersion&amp;lt;/code&amp;gt;: 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 &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt;: variable que guarda la última versión procesada. Debe comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualIDGroup&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt;: juntos forman el número con el que el sistema reconoce la paleta en los modos manuales. El primero indica el grupo: &amp;lt;code&amp;gt;#$FE&amp;lt;/code&amp;gt; para normal, &amp;lt;code&amp;gt;#$FC&amp;lt;/code&amp;gt; para cluster y &amp;lt;code&amp;gt;#$FD&amp;lt;/code&amp;gt; para extended. El segundo indica el tipo de sprite; en uno normal se utiliza &amp;lt;code&amp;gt;!CustomSpriteNumber,x&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
&lt;br /&gt;
También puedes crear grupos propios: por ejemplo, usar &amp;lt;code&amp;gt;manualIDGroup = #$FB&amp;lt;/code&amp;gt; para el jugador y &amp;lt;code&amp;gt;#$FA&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt; para distinguir los recursos dentro de cada uno. Los grupos &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$FD&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FC&amp;lt;/code&amp;gt; ya son utilizados por las rutinas de sprites normales, extended y cluster, respectivamente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada adicional&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* Si &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; debe contener el índice del sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: hay una paleta con la que se puede dibujar; desactivado si todavía no hay ninguna.&lt;br /&gt;
* Guarda el número de paleta en &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt; y actualiza &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt; cuando procesa la versión.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %PaletteAssignment(1, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!NormalPaletteAssignment,x&amp;quot;, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalVersion,x&amp;quot;, &amp;quot;!NormalLastVersion,x&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las variables de un sprite normal. &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; que termina la rutina, por lo que no debes añadir código después de ella.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignmentNoUpload (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; elige una paleta como &amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt;, pero deja pendiente la carga de sus colores. Permite aplicar después un efecto local y combinarlo con el global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteAssignmentNoUpload(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los parámetros son los mismos que en &amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt;. A recibe el offset de la tabla con 16 bits. &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt; deben comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;paletteVersion&amp;lt;/code&amp;gt; elige los colores de la lista del DynamicInfo: 0 para la primera paleta, 1 para la segunda, etc. &amp;lt;code&amp;gt;paletteAssignment&amp;lt;/code&amp;gt; decide el modo: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; automático, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; manual y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; manual sin cargar colores. &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: E permite el efecto global y PPP selecciona la paleta 8-F en manual. En automático, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F. Para aplicar después un efecto local sobre los colores del DynamicInfo, utiliza el modo automático o manual con carga.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: hay una paleta asignada; desactivado si no pudo obtenerse.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: número de la paleta asignada, de dos en dos entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt;: última versión procesada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: ID de la paleta seleccionada del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de sus colores.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
Usa los datos de &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
AssignPaletteForEffect:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %PaletteAssignmentNoUpload(1, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!NormalPaletteAssignment,x&amp;quot;, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalVersion,x&amp;quot;, &amp;quot;!NormalLastVersion,x&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Después de llamar a &amp;lt;code&amp;gt;AssignPaletteForEffect&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;, comprueba el carry y aplica el efecto usando los datos devueltos. Conserva Y y &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; para la llamada de concatenación.&lt;br /&gt;
&lt;br /&gt;
La macro ya termina la rutina con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. El código que aplica el efecto va después de la llamada &amp;lt;code&amp;gt;JSL AssignPaletteForEffect&amp;lt;/code&amp;gt;, no después de la macro dentro de esa rutina.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpritePaletteAssignment ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpritePaletteAssignment()&amp;lt;/code&amp;gt; utiliza las variables de paleta del tipo de sprite indicado. Es la macro utilizada por las rutinas PIXI de asignación.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%StandardSpritePaletteAssignment(type, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualIDGroup&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;#$FE&amp;lt;/code&amp;gt; para normal, &amp;lt;code&amp;gt;#$FC&amp;lt;/code&amp;gt; para cluster o &amp;lt;code&amp;gt;#$FD&amp;lt;/code&amp;gt; para extended.&lt;br /&gt;
* También puedes elegir un grupo propio, por ejemplo &amp;lt;code&amp;gt;#$FB&amp;lt;/code&amp;gt; para el jugador o &amp;lt;code&amp;gt;#$FA&amp;lt;/code&amp;gt; para otro tipo de entidad, siempre que esos valores no estén siendo utilizados por otro grupo de tu proyecto.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt;: variable o valor que identifica el tipo de sprite en los modos manuales.&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* Las variables de Dynamic Xtreme para paleta, opciones, versión y última versión del tipo seleccionado, preparadas como en &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;: guarda la paleta asignada en la tabla del sprite y devuelve el carry activado cuando se puede dibujar con ella.&lt;br /&gt;
&lt;br /&gt;
La macro ya incluye un &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt; y no añadas código después de la macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %StandardSpritePaletteAssignment(&amp;quot;Normal&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt; al eliminar los separadores.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpritePaletteAssignmentNoUpload ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpritePaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; utiliza las variables del tipo de sprite seleccionado para asignar la paleta, dejando pendiente la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%StandardSpritePaletteAssignmentNoUpload(type, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Recibe los mismos parámetros y datos que &amp;lt;code&amp;gt;%StandardSpritePaletteAssignment()&amp;lt;/code&amp;gt;. A debe contener el offset de la tabla de paletas con 16 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;: guarda la paleta asignada y devuelve el carry, Y, el ID en &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; y la dirección en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;, con las condiciones indicadas en esa entrada.&lt;br /&gt;
&lt;br /&gt;
La macro ya incluye un &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL AssignPaletteForEffect&amp;lt;/code&amp;gt;. El código que aplica el efecto va después de esa llamada.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
AssignPaletteForEffect:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %StandardSpritePaletteAssignmentNoUpload(&amp;quot;Normal&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== ReplacePalette (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ReplacePalette()&amp;lt;/code&amp;gt; sustituye los colores de una paleta que ya estás usando. Hace lo mismo que &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, pero tú eliges qué variables leer. Si otros sprites o códigos usan esa misma paleta, también verán los nuevos colores.&lt;br /&gt;
&lt;br /&gt;
Suele utilizarse después de una asignación sin carga, como &amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;. Primero obtienes la paleta asignada y después preparas en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; la dirección de los colores que quieres usar para reemplazarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%ReplacePalette(sprite, paletteOption, palette)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 obtiene el índice del sprite desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 0 utiliza variables independientes de ese índice.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor de las opciones de paleta. El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica si se aplica el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de la paleta de destino, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de los nuevos colores en BGR555.&lt;br /&gt;
* A en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Llámala cuando cambien los colores que quieres mostrar. Repetir la llamada cada frame obliga a preparar de nuevo la paleta y sus efectos.&lt;br /&gt;
&lt;br /&gt;
Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL ReplaceSpritePalette&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
ReplaceSpritePalette:&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;8&lt;br /&gt;
    STA $03&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
    %ReplacePalette(1, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyAlternatePalette&amp;lt;/code&amp;gt; es la dirección de una paleta insertada a partir de los recursos del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_alternate_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyAlternatePalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Cargar colores con TransferPalette ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros comunes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;: primer color que se cambiará, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Es un operando de 8 bits: &amp;lt;code&amp;gt;#$91&amp;lt;/code&amp;gt; empieza en el color 1 de la paleta 9; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; utiliza el número guardado en esa scratch.&lt;br /&gt;
* &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt;: cantidad de bytes que se copiarán. Es un valor conocido al ensamblar, &#039;&#039;&#039;sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;&#039;&#039;&#039;: &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; copia 15 colores. Debe ser mayor que cero y par, y la carga no debe pasar del último color de CGRAM.&lt;br /&gt;
* &amp;lt;code&amp;gt;GlobalEffect&amp;lt;/code&amp;gt;: utiliza &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; para cargar sin efecto global o &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; para que la paleta reciba el efecto global. Es una opción fija de la llamada, no una variable de RAM.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué hace GlobalEffect&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Comportamiento&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;GlobalEffect = 1&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas y resultado comunes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Entra con A, X e Y en modo de 8 bits y con el banco de datos y la direct page habituales de Dynamic Xtreme.&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y pueden cambiar y quedan en modo de 8 bits. Las llamadas pueden modificar &amp;lt;code&amp;gt;$68-$6D&amp;lt;/code&amp;gt;; las variantes &amp;lt;code&amp;gt;FromAddress&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FromTable&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Resource&amp;lt;/code&amp;gt; también utilizan &amp;lt;code&amp;gt;$65-$67&amp;lt;/code&amp;gt;.&lt;br /&gt;
* No incluyen &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;: el código continúa después de la macro.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteFromAddress ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteFromAddress()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteFromAddress(Address, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Address&amp;lt;/code&amp;gt;: dirección de origen completa, sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Paleta 9, colores 1-F, con efecto global.&lt;br /&gt;
    %TransferPaletteFromAddress(!PaletteMyPalette, #$91, $001E, 1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; se genera al instalar una paleta declarada en &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; de un DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase: se eliminan espacios, guiones bajos y guiones, y se pone en mayúscula la inicial de cada palabra. Por ejemplo, &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteFromPointer ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteFromPointer()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteFromPointer(Pointer, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Pointer&amp;lt;/code&amp;gt;: dirección del primer byte de la scratch, sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;. Los tres bytes deben contener la dirección de origen en orden bajo, alto y banco. Por ejemplo, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Preparar la dirección de la paleta en $02-$04.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!PaletteMyPalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.b #!PaletteMyPalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
&lt;br /&gt;
    ; Paleta 9, colores 1-F, sin efecto global.&lt;br /&gt;
    %TransferPaletteFromPointer($02, #$91, $001E, 0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; se genera desde una paleta del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteFromTable ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteFromTable()&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;$65-$67&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteFromTable(TableAddr, TableBNK, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;TableAddr&amp;lt;/code&amp;gt;: operando que se lee con A de 16 bits para obtener los dos bytes de dirección.&lt;br /&gt;
* &amp;lt;code&amp;gt;TableBNK&amp;lt;/code&amp;gt;: operando que se lee con A de 8 bits para obtener el banco.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; $02-$03 contiene la dirección y $04 contiene el banco.&lt;br /&gt;
    %TransferPaletteFromTable(&amp;quot;$02&amp;quot;, &amp;quot;$04&amp;quot;, #$91, $001E, 1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A diferencia de &amp;lt;code&amp;gt;FromPointer&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteResource ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteResource()&amp;lt;/code&amp;gt; carga una paleta registrada en el DynamicInfo utilizando su tamaño completo. No necesitas escribir su dirección ni su cantidad de bytes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferPaletteResource(Name, CGRAMOffset, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Name&amp;lt;/code&amp;gt;: nombre normalizado de la paleta, sin prefijo &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt; y sin extensión. La macro utiliza &amp;lt;code&amp;gt;!Palette&amp;amp;lt;Name&amp;amp;gt;&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Palette&amp;amp;lt;Name&amp;amp;gt;Size&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; MyPalette contiene 15 colores.&lt;br /&gt;
    %TransferPaletteResource(MyPalette, #$91, 1)&lt;br /&gt;
    BCS .Accepted&lt;br /&gt;
    ; No se aceptó la carga directa: volver a intentarlo después.&lt;br /&gt;
    RTL&lt;br /&gt;
.Accepted&lt;br /&gt;
    ; Continuar con el resto del código.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo continúa en &amp;lt;code&amp;gt;.Accepted&amp;lt;/code&amp;gt; si se aceptó la carga directa o se prepararon los colores para el efecto global. El &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; pertenece al ejemplo, no a la macro.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; corresponde a los defines &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteMyPaletteSize&amp;lt;/code&amp;gt;, generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; desde la sección &amp;lt;code&amp;gt;Palettes&amp;lt;/code&amp;gt; del DynamicInfo. El nombre usa PascalCase eliminando espacios, guiones bajos y guiones: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;. Esta llamada no utiliza los defines &amp;lt;code&amp;gt;!Resource...&amp;lt;/code&amp;gt; de la sección &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; ni las paletas convertidas RGB/HSL de un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferPaletteResourceWithLength ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferPaletteResourceWithLength()&amp;lt;/code&amp;gt; utiliza la dirección de una paleta registrada, pero permite copiar solo la cantidad de bytes que indiques.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%TransferPaletteResourceWithLength(Name, CGRAMOffset, Length, GlobalEffect)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Name&amp;lt;/code&amp;gt;: nombre normalizado de la paleta, igual que en &amp;lt;code&amp;gt;%TransferPaletteResource()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;Length&amp;lt;/code&amp;gt;: cantidad de bytes que se copiarán, sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;. No debe superar el tamaño del recurso.&lt;br /&gt;
* Los demás parámetros y el carry funcionan como se explica en [[#Cargar colores con TransferPalette|Cargar colores con TransferPalette]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Copiar 4 colores al comienzo de la paleta 9, sin efecto global.&lt;br /&gt;
    %TransferPaletteResourceWithLength(MyPalette, #$90, $0008, 0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; utiliza el define &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt;, generado desde una paleta del DynamicInfo y publicado en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TransferPaletteCommon&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TransferPaletteData&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Efectos de paleta ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 [[es/Dynamic_Xtreme_files_and_formats#Tipos_de_efectos|Tipos de efectos]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;¿Qué llamada necesitas?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Quieres… !! Utiliza…&lt;br /&gt;
|-&lt;br /&gt;
| Teñir una paleta o cambiar su tono, saturación o luminosidad. || &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MixAndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Pasar de una paleta a otra. || &amp;lt;code&amp;gt;PaletteTransition&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Aplicar un efecto que ya definiste en un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. || &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DoEffectAndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Darle un efecto propio a un sprite y conservar además el efecto global. || &amp;lt;code&amp;gt;ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; o su variante HSL, después de asignar la paleta sin carga.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para calcular un efecto directamente, el proceso habitual es preparar los colores originales con &amp;lt;code&amp;gt;SetRGBBase&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;SetHSLBase&amp;lt;/code&amp;gt; y después aplicar el cambio. Los ejemplos utilizan las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt;, que trabajan con las copias de paleta de Dynamic Xtreme y evitan escribir direcciones de memoria.&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, estas ya se encargan de preparar los colores y completar su carga.&lt;br /&gt;
&lt;br /&gt;
En los ejemplos, prepara A en modo de 8 bits antes de llamar a las macros.&lt;br /&gt;
&lt;br /&gt;
==== Preparar los colores: SetRGBBase y SetHSLBase ====&lt;br /&gt;
&lt;br /&gt;
Antes de modificar los colores, necesitas una copia con la que calcular el efecto. &amp;lt;code&amp;gt;%SetRGBBase()&amp;lt;/code&amp;gt; prepara esa copia para efectos RGB; &amp;lt;code&amp;gt;%SetHSLBase()&amp;lt;/code&amp;gt; la prepara para HSL. Si los colores originales no cambiaron, puedes reutilizarla en los siguientes frames.&lt;br /&gt;
&lt;br /&gt;
En las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; solo indicas el primer color y cuántos colores quieres preparar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%SetRGBBaseDefault(offset, length)&lt;br /&gt;
%SetHSLBaseDefault(offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; es el número del primer color y &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; es la cantidad. Por ejemplo, &amp;lt;code&amp;gt;#$0081&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;#$000F&amp;lt;/code&amp;gt; seleccionan los 15 colores visibles de la paleta 8.&lt;br /&gt;
&lt;br /&gt;
Si necesitas elegir tú las direcciones donde leer y guardar los colores, utiliza las versiones completas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%SetRGBBase(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%SetHSLBase(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;%SetRGBBaseDefault(offset, length)&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%SetHSLBaseDefault(offset, length)&amp;lt;/code&amp;gt; leen de &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; y guardan el resultado en &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: preparar una paleta de sprites&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Paleta 8, sin incluir su primer color transparente.&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
    ; Para trabajar en HSL, utiliza esta variante en su lugar:&lt;br /&gt;
    ; %SetHSLBaseDefault(#$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$81&amp;lt;/code&amp;gt; es el segundo color de la paleta 8: la paleta comienza en el color &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; y se procesan los 15 siguientes.&lt;br /&gt;
&lt;br /&gt;
==== Mezclar colores: Mix y MixAndMerge ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Los parámetros &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; indican el color que quieres alcanzar, entre 0 y 31. Los parámetros &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#$7F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para RGB, los valores 1, 2 y 3 corresponden a rojo, verde y azul. Para HSL corresponden a tono, saturación y luminosidad.&lt;br /&gt;
&lt;br /&gt;
El final del nombre indica qué componentes se modifican:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! RGB !! HSL !! Componentes modificados&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;H&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;L&amp;lt;/code&amp;gt; || Uno.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GB&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SL&amp;lt;/code&amp;gt; || Dos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RGB&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HSL&amp;lt;/code&amp;gt; || Los tres.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada combinación está disponible como &amp;lt;code&amp;gt;Mix...&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixAndMerge...&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;MixAndMerge...Default&amp;lt;/code&amp;gt;. Por ejemplo: &amp;lt;code&amp;gt;%MixR()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%MixAndMergeR()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%MixAndMergeRDefault()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; omiten las direcciones.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%MixRGB(r1, r2, r3, v1, v2, v3, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%MixAndMergeRG(r1, r2, v1, v2, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%MixAndMergeLDefault(r3, v3, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo RGB: teñir de rojo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; Preparar los colores originales de la paleta 8.&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
    ; Acercar los tres componentes a un rojo puro, aproximadamente a la mitad.&lt;br /&gt;
    %MixAndMergeRGBDefault(#$40, #$40, #$40, #$1F, #$00, #$00, #$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los tres primeros valores &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt; indican la intensidad del cambio para rojo, verde y azul. Los siguientes, &amp;lt;code&amp;gt;#$1F, #$00, #$00&amp;lt;/code&amp;gt;, indican el rojo puro al que se acercarán. Los dos últimos seleccionan los 15 colores de la paleta 8.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo HSL: aclarar la paleta&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %SetHSLBaseDefault(#$0081, #$000F)&lt;br /&gt;
    %MixAndMergeLDefault(#$40, #$1F, #$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aquí solo cambia la luminosidad: &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt; aplica aproximadamente la mitad del cambio y &amp;lt;code&amp;gt;#$1F&amp;lt;/code&amp;gt; indica la luminosidad máxima. Este es un ejemplo independiente del anterior.&lt;br /&gt;
&lt;br /&gt;
==== Cambiar entre paletas: PaletteTransition ====&lt;br /&gt;
&lt;br /&gt;
Estas macros acercan cada color de la paleta original al color correspondiente de otra paleta. A diferencia de &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt;, cada color tiene su propio destino. Sirven, por ejemplo, para pasar de los colores normales de un sprite a una paleta de daño.&lt;br /&gt;
&lt;br /&gt;
Las variantes son &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransitionHSL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransitionRGBAndMerge&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PaletteTransitionHSLAndMerge&amp;lt;/code&amp;gt;. Las dos variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; también tienen versión &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteTransitionRGB(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%PaletteTransitionHSLAndMerge(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%PaletteTransitionRGBAndMergeDefault(r1, r2, r3, targetpal, targetpalbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;targetpal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;targetpalbnk&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: calcular un paso intermedio de una transición&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; Este ejemplo trabaja con los primeros 15 colores de la copia de paletas.&lt;br /&gt;
    %SetRGBBaseDefault(#$0000, #$000F)&lt;br /&gt;
    %PaletteTransitionRGBAndMergeDefault(#$40, #$40, #$40, #!PaletteMyTargetRGB, #!PaletteMyTargetRGB&amp;gt;&amp;gt;16, #$0000, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo supone que &amp;lt;code&amp;gt;!PaletteMyTargetRGB&amp;lt;/code&amp;gt; corresponde a una paleta de destino RGB generada al instalar un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; de transición. Su dirección queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_target&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyTarget&amp;lt;/code&amp;gt;. Para HSL se utiliza la paleta convertida a HSL y la macro correspondiente.&lt;br /&gt;
&lt;br /&gt;
==== Aplicar un efecto de un archivo: DoEffect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DoEffect()&amp;lt;/code&amp;gt; aplica un efecto de un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%DoEffect(effect, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%DoEffectAndMerge(effect, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%DoEffectAndMergeDefaultRGB(effect, offset, length)&lt;br /&gt;
%DoEffectAndMergeDefaultHSL(effect, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;effect&amp;lt;/code&amp;gt;: ID del efecto, como &amp;lt;code&amp;gt;#!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt;.&lt;br /&gt;
* El origen debe contener colores RGB o HSL separados, según el efecto elegido.&lt;br /&gt;
* &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; guarda el resultado con 3 bytes por color para poder seguir modificándolo.&lt;br /&gt;
* &amp;lt;code&amp;gt;DoEffectAndMerge&amp;lt;/code&amp;gt; guarda colores en formato de SNES. Las variantes &amp;lt;code&amp;gt;DefaultRGB&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DefaultHSL&amp;lt;/code&amp;gt; eligen la base correspondiente y escriben en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: aplicar un efecto RGB a la paleta 8&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
    %DoEffectAndMergeDefaultRGB(#!PaletteEffectIDMyEffect0, #$81, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; se genera desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. El número final identifica el efecto dentro del archivo. Si el efecto trabaja en HSL, prepara la base HSL y utiliza &amp;lt;code&amp;gt;%DoEffectAndMergeDefaultHSL()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Convertir entre RGB y HSL ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%RGBToHSL()&amp;lt;/code&amp;gt; convierte colores RGB a HSL y &amp;lt;code&amp;gt;%HSLToRGB()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%RGBToHSL(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%HSLToRGB(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: convertir la base RGB a HSL&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %RGBToHSL(#DX_PPU_CGRAM_BaseRGBPalette, #DX_PPU_CGRAM_BaseRGBPalette&amp;gt;&amp;gt;16, #DX_PPU_CGRAM_BaseHSLPalette, #DX_PPU_CGRAM_BaseHSLPalette&amp;gt;&amp;gt;16, #$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Combinar un efecto propio con el global ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Suelen utilizarse después de &amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%ConcatenateRGBPaletteEffectToGlobal(sprite, paletteOption, palette)&lt;br /&gt;
%ConcatenateHSLPaletteEffectToGlobal(sprite, paletteOption, palette)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 recupera el índice del sprite desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 0 permite utilizar variables propias.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor de las opciones de paleta; activa el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; para incluir el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable que contiene la paleta asignada, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos.&lt;br /&gt;
* A de 16 bits: ID del efecto local RGB o HSL, según la macro.&lt;br /&gt;
* X de 8 bits: copia del valor de la paleta asignada.&lt;br /&gt;
* Y de 8 bits: conserva el valor devuelto por la asignación sin carga.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de los colores originales preparada por esa asignación.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: completar una asignación sin carga&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
; Llamar esta rutina con JSL después de asignar la paleta sin carga.&lt;br /&gt;
; Deben conservarse Y y $02-$04 de aquella llamada.&lt;br /&gt;
ApplyLocalEffect:&lt;br /&gt;
    LDA !NormalPalette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyEffect0&lt;br /&gt;
    %ConcatenateRGBPaletteEffectToGlobal(1, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; se genera desde un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. Para un efecto HSL, utiliza la macro HSL. Si usas Y para leer una tabla de efectos, guarda su valor con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; y recupéralo con &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; antes de concatenar.&lt;br /&gt;
&lt;br /&gt;
==== Elegir las direcciones y combinar varios efectos ====&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; 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:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;src&amp;lt;/code&amp;gt;: dónde leer los colores originales; &amp;lt;code&amp;gt;srcbnk&amp;lt;/code&amp;gt;: su banco.&lt;br /&gt;
* &amp;lt;code&amp;gt;dst&amp;lt;/code&amp;gt;: dónde guardar el resultado; &amp;lt;code&amp;gt;dstbnk&amp;lt;/code&amp;gt;: su banco. El destino debe ser un espacio de RAM que tu código pueda utilizar.&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: primer color que se procesará, contando desde 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt;: cantidad de colores que se procesarán.&lt;br /&gt;
&lt;br /&gt;
Para indicar una dirección fija, se utiliza &amp;lt;code&amp;gt;#Nombre&amp;lt;/code&amp;gt; para la dirección y &amp;lt;code&amp;gt;#Nombre&amp;gt;&amp;gt;16&amp;lt;/code&amp;gt; para su banco, como en el ejemplo de conversión RGB a HSL. También puedes pasar variables que contengan esos datos.&lt;br /&gt;
&lt;br /&gt;
El espacio necesario depende del paso que estés realizando:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Operación !! Lee !! Guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SetRGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SetHSLBase&amp;lt;/code&amp;gt; || Paleta normal: 2 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransition&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; sin &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| Variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Paleta normal: 2 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RGBToHSL&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;HSLToRGB&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si quieres aplicar dos efectos seguidos, el primero debe guardar sus colores separados, sin &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt;. El segundo lee ese resultado y utiliza &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; para dejar la paleta lista para cargarla. Si uno trabaja en RGB y el otro en HSL, convierte los colores entre ambos pasos.&lt;br /&gt;
&lt;br /&gt;
Las macros utilizan memoria temporal, entre otras las direcciones &amp;lt;code&amp;gt;$45-$50&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$51-$53&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8C&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8E&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$D5-$D7&amp;lt;/code&amp;gt;, según la operación. No guardes en ellas datos que necesites conservar después de la llamada.&lt;br /&gt;
&lt;br /&gt;
=== PPU ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué llamada elegir&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Necesitas… !! VRAM !! CGRAM&lt;br /&gt;
|-&lt;br /&gt;
| Indicar la dirección de origen y su banco por separado. || &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Indicar una dirección completa y dejar que la macro obtenga el banco. || &amp;lt;code&amp;gt;TransferToVRAMFromAddr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferToCGRAMFromAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Cargar un recurso completo registrado en Dynamic Xtreme. || &amp;lt;code&amp;gt;TransferResourceToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferResourceToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Cargar solo una cantidad de bytes de un recurso. || &amp;lt;code&amp;gt;TransferResourceToVRAMWithLenght&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferResourceToCGRAMWithLenght&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las versiones normales comprueban si la transferencia cabe dentro del límite de bytes del frame:&lt;br /&gt;
&lt;br /&gt;
* Carry activado: la transferencia quedó programada.&lt;br /&gt;
* Carry desactivado: no se programó porque superaría ese límite. Tu código puede intentarlo en otro frame.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== TransferToVRAM ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; programa una copia de gráficos desde ROM o RAM hacia VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToVRAM(VRAMOffset, ResourceAddr, ResourceBNK, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;VRAMOffset&amp;lt;/code&amp;gt;: dirección de destino en VRAM, expresada en palabras de 2 bytes. Por ejemplo, copiar &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes desde &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; ocupa las palabras &amp;lt;code&amp;gt;$6000-$60FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;ResourceAddr&amp;lt;/code&amp;gt;: dirección de origen dentro de su banco.&lt;br /&gt;
* &amp;lt;code&amp;gt;ResourceBNK&amp;lt;/code&amp;gt;: banco del origen.&lt;br /&gt;
* &amp;lt;code&amp;gt;Lenght&amp;lt;/code&amp;gt;: cantidad de bytes que se copiarán. Se conserva esta escritura del nombre porque así aparece en la macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: programar la carga de gráficos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToVRAM(#$6000, #!ResourceMyGraphics, #!ResourceMyGraphics&amp;gt;&amp;gt;16, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
    ; La copia se realizará en el próximo NMI.&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; es la dirección de un recurso registrado desde un DynamicInfo; queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;. La cantidad de bytes solicitada debe existir en ese recurso.&lt;br /&gt;
&lt;br /&gt;
==== TransferToVRAMFromAddr ====&lt;br /&gt;
&lt;br /&gt;
Hace la misma copia, pero recibe la dirección completa del origen. La macro separa su dirección y banco por ti.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToVRAMFromAddr(VRAMOffset, addr, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; se escribe sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;; los otros parámetros se entregan como en &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferToVRAMFromAddr(#$6000, !ResourceMyGraphics, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; se genera desde un recurso del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferResourceToVRAM y TransferResourceToVRAMWithLenght ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferResourceToVRAM(VRAMOffset, ResourceName)&lt;br /&gt;
%TransferResourceToVRAMWithLenght(VRAMOffset, ResourceName, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para un recurso cuyos defines sean &amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceMyGraphicsSize&amp;lt;/code&amp;gt;, escribe &amp;lt;code&amp;gt;&amp;quot;MyGraphics&amp;quot;&amp;lt;/code&amp;gt; como &amp;lt;code&amp;gt;ResourceName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: cargar el recurso completo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToVRAM(#$6000, &amp;quot;MyGraphics&amp;quot;)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: cargar solo sus primeros $0200 bytes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToVRAMWithLenght(#$6000, &amp;quot;MyGraphics&amp;quot;, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El nombre y el tamaño se obtienen de los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; al instalar los recursos del DynamicInfo. Utiliza el nombre normalizado: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;, eliminando los separadores y poniendo en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
==== TransferToCGRAM ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt; programa una copia de colores desde ROM o RAM hacia una paleta de SNES.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToCGRAM(CGRAMOffset, TableAddr, TableBNK, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;: número del primer color de destino, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Por ejemplo, la paleta 8 comienza en el color &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;TableAddr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TableBNK&amp;lt;/code&amp;gt;: dirección y banco de los colores que se van a copiar.&lt;br /&gt;
* &amp;lt;code&amp;gt;Lenght&amp;lt;/code&amp;gt;: cantidad de bytes. Cada color ocupa 2 bytes; 15 colores ocupan &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar los 15 colores visibles de la paleta 8&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToCGRAM(#$81, #DX_PPU_CGRAM_PaletteWriteMirror+$0102, #DX_PPU_CGRAM_PaletteWriteMirror&amp;gt;&amp;gt;16, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Este ejemplo toma el resultado de un efecto guardado en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;. El desplazamiento &amp;lt;code&amp;gt;$0102&amp;lt;/code&amp;gt; corresponde al color &amp;lt;code&amp;gt;$81&amp;lt;/code&amp;gt;, porque cada color ocupa 2 bytes. Se omite el primer color de la paleta, que es transparente en sprites.&lt;br /&gt;
&lt;br /&gt;
==== TransferToCGRAMFromAddr ====&lt;br /&gt;
&lt;br /&gt;
Hace la misma copia de colores, pero recibe la dirección completa del origen. Escribe &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToCGRAMFromAddr(CGRAMOffset, addr, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToCGRAMFromAddr(#$81, DX_PPU_CGRAM_PaletteWriteMirror+$0102, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== TransferResourceToCGRAM y TransferResourceToCGRAMWithLenght ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferResourceToCGRAM(CGRAMOffset, ResourceName)&lt;br /&gt;
%TransferResourceToCGRAMWithLenght(CGRAMOffset, ResourceName, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar un recurso completo de colores&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToCGRAM(#$80, &amp;quot;MyColors&amp;quot;)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar solo 15 colores&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToCGRAMWithLenght(#$81, &amp;quot;MyColors&amp;quot;, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Estos ejemplos suponen un recurso general de colores con los defines &amp;lt;code&amp;gt;!ResourceMyColors&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceMyColorsSize&amp;lt;/code&amp;gt;, generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; desde un DynamicInfo. Utiliza el nombre normalizado: &amp;lt;code&amp;gt;my_colors&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyColors&amp;lt;/code&amp;gt;. En el segundo ejemplo, el recurso debe comenzar con los 15 colores que se quieren copiar, sin anteponer el color transparente.&lt;br /&gt;
&lt;br /&gt;
==== Variantes Forced ====&lt;br /&gt;
&lt;br /&gt;
Todas las transferencias anteriores tienen una variante cuyo nombre comienza con &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;. Programa la copia aunque supere el límite de bytes del frame. La cantidad copiada también se suma al total de ese frame.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! VRAM !! CGRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferToVRAMFromAddr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferToCGRAMFromAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferResourceToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferResourceToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferResourceToVRAMWithLenght&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferResourceToCGRAMWithLenght&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Reciben los mismos parámetros que las versiones sin &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %ForcedTransferResourceToVRAM(#$6000, &amp;quot;MyGraphics&amp;quot;)&lt;br /&gt;
    ; No se comprueba el carry en esta variante.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt; corresponde al recurso &amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, generado desde el DynamicInfo. Se utiliza el nombre normalizado, como &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Matemáticas ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Prepara A en modo de 8 bits antes de llamarlas. Las macros no cambian por ti el tamaño de A, X o Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cómo escribir los argumentos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Mul&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Div&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MulAfterMul&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DivAfterDiv&amp;lt;/code&amp;gt; pegan el argumento directamente después de &amp;lt;code&amp;gt;LDA&amp;lt;/code&amp;gt;. Escribe el argumento entre comillas con un espacio al principio: &amp;lt;code&amp;gt;&amp;quot; #$05&amp;quot;&amp;lt;/code&amp;gt; produce &amp;lt;code&amp;gt;LDA #$05&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También puedes comenzar el argumento con &amp;lt;code&amp;gt;.b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;.l&amp;lt;/code&amp;gt; para elegir cómo se escribe el acceso a memoria. Por ejemplo, si &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; contiene el número que quieres multiplicar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot;.b $02&amp;quot;, &amp;quot; #$07&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esto genera &amp;lt;code&amp;gt;LDA.b $02&amp;lt;/code&amp;gt; para leer el primer número y &amp;lt;code&amp;gt;LDA #$07&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Las variantes con &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt;, además de &amp;lt;code&amp;gt;MulAfterDiv&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DivAfterMul&amp;lt;/code&amp;gt;, ya añaden un espacio antes de los argumentos. En ellas puedes escribir los valores normalmente, como &amp;lt;code&amp;gt;%MulW(#$05, #$07)&amp;lt;/code&amp;gt;. En la implementación actual no se pasan los sufijos &amp;lt;code&amp;gt;.b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;.l&amp;lt;/code&amp;gt; de esta misma manera a esas variantes, porque el espacio que añaden quedaría entre &amp;lt;code&amp;gt;LDA&amp;lt;/code&amp;gt; y el sufijo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;¿Qué significa la W?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El hardware necesita un pequeño tiempo para terminar el cálculo. Las macros con &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; incluyen esa espera: puedes leer el resultado inmediatamente después. Las versiones sin &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los resultados se leen mediante estos defines:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!MultiplicationResult&amp;lt;/code&amp;gt;: resultado de multiplicar, de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;!DivisionResult&amp;lt;/code&amp;gt;: cociente de la división, de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;!RemainderResult&amp;lt;/code&amp;gt;: resto de la división, de 16 bits.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Mul y MulW ====&lt;br /&gt;
&lt;br /&gt;
Multiplican dos valores de 8 bits y producen un resultado de 16 bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Mul(a, b)&lt;br /&gt;
%MulW(a, b)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; pueden ser valores inmediatos, como &amp;lt;code&amp;gt;#$06&amp;lt;/code&amp;gt;, o variables de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: 6 × 7 = 42&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %MulW(#$06, #$07)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $002A, es decir, 42&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La llamada sin espera sería &amp;lt;code&amp;gt;%Mul(&amp;quot; #$06&amp;quot;, &amp;quot; #$07&amp;quot;)&amp;lt;/code&amp;gt;. En ese caso no leas el resultado inmediatamente: ejecuta antes otro código que no utilice el hardware de multiplicación o división.&lt;br /&gt;
&lt;br /&gt;
==== Div y DivW ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Div(ah, al, b)&lt;br /&gt;
%DivW(ah, al, b)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;ah&amp;lt;/code&amp;gt;: byte alto del número que quieres dividir.&lt;br /&gt;
* &amp;lt;code&amp;gt;al&amp;lt;/code&amp;gt;: byte bajo del mismo número.&lt;br /&gt;
* &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;: número por el que divides, entre 1 y 255.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: 300 ÷ 7 = 42, con resto 6&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; 300 = $012C: byte alto $01, byte bajo $2C.&lt;br /&gt;
    %DivW(#$01, #$2C, #$07)&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $002A, es decir, 42&lt;br /&gt;
    LDA !RemainderResult         ; A = $0006&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
También puedes pasar una variable de 16 bits como dos argumentos: &amp;lt;code&amp;gt;%DivW(MiNumero+1, MiNumero, #$07)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;MiNumero&amp;lt;/code&amp;gt; representa aquí una variable definida por tu código.&lt;br /&gt;
&lt;br /&gt;
==== Continuar desde el resultado anterior ====&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;AfterMul&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;AfterDiv&amp;lt;/code&amp;gt; toman el resultado del cálculo anterior como primer número. Solo debes indicar el segundo número.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Macro !! Cálculo que realiza&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MulAfterMul(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MulWAfterMul(b)&amp;lt;/code&amp;gt; || Toma los 8 bits bajos del resultado de la multiplicación anterior y los multiplica por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MulAfterDiv(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MulWAfterDiv(b)&amp;lt;/code&amp;gt; || Toma los 8 bits bajos del cociente anterior y los multiplica por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DivAfterMul(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DivWAfterMul(b)&amp;lt;/code&amp;gt; || Divide el resultado completo de la multiplicación anterior por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DivAfterDiv(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DivWAfterDiv(b)&amp;lt;/code&amp;gt; || Divide el cociente completo de la división anterior por b.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La W sigue indicando que puedes leer el nuevo resultado inmediatamente después. Las variantes &amp;lt;code&amp;gt;After...&amp;lt;/code&amp;gt; ya incluyen la espera que necesitan para tomar el resultado del cálculo anterior.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dos multiplicaciones, (6 × 7) × 2 = 84&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot; #$06&amp;quot;, &amp;quot; #$07&amp;quot;)&lt;br /&gt;
    %MulWAfterMul(#$02)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $0054, es decir, 84&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dividir y después multiplicar, (100 ÷ 4) × 3 = 75&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Div(&amp;quot; #$00&amp;quot;, &amp;quot; #$64&amp;quot;, &amp;quot; #$04&amp;quot;)&lt;br /&gt;
    %MulWAfterDiv(#$03)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $004B, es decir, 75&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: multiplicar y después dividir, (20 × 15) ÷ 4 = 75&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot; #$14&amp;quot;, &amp;quot; #$0F&amp;quot;)&lt;br /&gt;
    %DivWAfterMul(#$04)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $004B, es decir, 75&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dos divisiones, (300 ÷ 3) ÷ 4 = 25&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Div(&amp;quot; #$01&amp;quot;, &amp;quot; #$2C&amp;quot;, &amp;quot; #$03&amp;quot;)&lt;br /&gt;
    %DivWAfterDiv(#$04)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $0019, es decir, 25&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En las multiplicaciones, el primer número siempre se limita a 8 bits. Si el resultado anterior era mayor que 255, &amp;lt;code&amp;gt;MulAfterMul&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;MulAfterDiv&amp;lt;/code&amp;gt; solo utilizará su byte bajo. Las divisiones de esta tabla sí toman el resultado anterior completo, de 16 bits.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21357</id>
		<title>es/Dynamic Xtreme UberASM guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21357"/>
		<updated>2026-10-24T05:58:47Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_UberASM_guide}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo utilizar Dynamic Xtreme desde UberASM para configurar los recursos de un nivel y crear cambios de gráficos y colores durante el juego. Se incluyen ejemplos para reservar paletas, elegir el espacio disponible para sprites dinámicos, crear animaciones y modificar los gráficos del jugador.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Tener UberASMTool instalado y configurado para insertar códigos en tu ROM.&lt;br /&gt;
* Tener Dynamic Xtreme instalado con las funciones necesarias para el ejemplo que quieras utilizar. Consulta la [[es/Dynamic_Xtreme_Quick_Start|guía de inicio rápido]] para su instalación.&lt;br /&gt;
&lt;br /&gt;
Para consultar los parámetros de una llamada o el uso de una variable, utiliza la [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]].&lt;br /&gt;
&lt;br /&gt;
== Preparar los ejemplos ==&lt;br /&gt;
&lt;br /&gt;
Cada ejemplo es independiente. Guarda el código de nivel en la carpeta correspondiente de UberASMTool y añádelo a su lista. Si reúnes varios ejemplos en un archivo, combina sus bloques &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; para no repetir las mismas etiquetas.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt; prepara datos durante la carga del nivel. Se utiliza aquí para reservar paletas antes de que las reclamen los sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; prepara las opciones al entrar al nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; ejecuta el código durante el juego, una vez por frame.&lt;br /&gt;
&lt;br /&gt;
Los defines y macros de Dynamic Xtreme deben estar disponibles en UberASMTool mediante la integración realizada durante la instalación. Si utilizas gráficos, paletas o efectos adicionales, decláralos en el ASM mediante los includes correspondientes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MyResources.dynamicinfo&amp;quot;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/MyEffect.paleffect&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las rutas son relativas al ASM. Incluye únicamente los archivos que utiliza tu ejemplo. También puedes usar las carpetas tradicionales de Dynamic Xtreme, como se explica en [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
&lt;br /&gt;
Después de añadir o modificar estos recursos, instala primero Dynamic Xtreme y después UberASMTool. Si solo cambias la lógica del ASM, basta con volver a ejecutar UberASMTool.&lt;br /&gt;
&lt;br /&gt;
== Reservar paletas para otros recursos ==&lt;br /&gt;
&lt;br /&gt;
Si una animación, un HUD u otro recurso necesita una paleta fija, conviene reservarla para que Dynamic Xtreme no la elija al asignar colores a los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
Para reservarla, escribe &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; en su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt;. Cada entrada ocupa 2 bytes. Por ejemplo, la paleta 9 utiliza el desplazamiento &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;: 9 × 2.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$FFFE&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_ID+$12    ; Reservar la paleta 9&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para reservar varias, escribe el mismo valor en sus entradas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Paleta !! Desplazamiento&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| A || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| B || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| C || &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| D || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| E || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| F || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La reserva impide que la asignación automática reclame esa paleta; no carga colores por sí misma. Un recurso configurado para utilizarla manualmente todavía puede cambiar sus colores, por lo que no debes asignársela también a otro recurso que necesite una paleta diferente.&lt;br /&gt;
&lt;br /&gt;
== Elegir el espacio de VRAM para sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Los sprites dinámicos necesitan una parte de VRAM donde cargar sus poses. Elige un espacio que no estés utilizando para gráficos fijos del nivel.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para permitir que utilicen SP4:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si necesitas más espacio y el nivel lo permite, puedes elegir &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; para SP3 y SP4, o &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt; para SP2, SP3 y SP4. Hay más opciones, incluidas medias páginas y configuraciones para compartir espacio con el jugador o DSX.&lt;br /&gt;
&lt;br /&gt;
Los defines disponibles están en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y en la [[es/Dynamic_Xtreme_ASM_API#Configuraciones_de_espacio_para_poses_dinámicas|tabla de configuraciones de la API]]. Configura el espacio antes de que el nivel empiece a cargar poses; cambiarlo no elimina automáticamente las poses que ya estaban en VRAM.&lt;br /&gt;
&lt;br /&gt;
== Configurar la cantidad de datos que se transfieren por frame ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; indica cuántos bytes pueden programar las cargas normales de Dynamic Xtreme durante un frame. Lo comparten las poses dinámicas, las animaciones y las demás transferencias realizadas con sus macros.&lt;br /&gt;
&lt;br /&gt;
El valor predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Este ejemplo lo aumenta a &amp;lt;code&amp;gt;$0A00&amp;lt;/code&amp;gt;, equivalente a 2560 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0A00&lt;br /&gt;
    STA.l DX_Dynamic_MaxDataPerFrame&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Subirlo permite intentar más cargas durante el mismo frame, pero no aumenta el tiempo que tiene SNES para copiarlas. Si la cantidad total es excesiva, pueden aparecer problemas visuales. Ajusta el valor según el nivel y comprueba el resultado con sus sprites y animaciones funcionando juntos.&lt;br /&gt;
&lt;br /&gt;
Las macros normales devuelven el carry desactivado si una carga no cabe en el límite. En ese caso, conserva lo que ya se muestra y vuelve a intentarlo después. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; se saltan la comprobación y también suman sus bytes al total.&lt;br /&gt;
&lt;br /&gt;
== Crear animaciones de gráficos ==&lt;br /&gt;
&lt;br /&gt;
Una animación de tiles se consigue copiando distintas imágenes al mismo lugar de VRAM. Los tiles del nivel siguen apuntando al mismo lugar, pero los gráficos que contienen van cambiando.&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las primeras cuatro imágenes de &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;, con &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes por imagen, y cambia de imagen cada ocho frames. El archivo se registra como recurso general, no como pose de sprite dinámico.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;, junto a &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ASM del nivel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
!AnimationGraphics = !ResourceSMMArrow&lt;br /&gt;
!Destination = !BG2Line0&lt;br /&gt;
!BytesPerFrame = $0200&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    %ForcedTransferToVRAMFromAddr(#!Destination, !AnimationGraphics, #!BytesPerFrame)&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $9D&lt;br /&gt;
    ORA $13D4|!addr&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    ; Cambiar de imagen cada ocho frames.&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$07&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    ; Obtener 0, $0200, $0400 o $0600 como desplazamiento en el archivo.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$0018&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC.w #!AnimationGraphics&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    %TransferToVRAM(#!Destination, $00, #(!AnimationGraphics&amp;gt;&amp;gt;16), #!BytesPerFrame)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt; es la dirección que se genera al instalar el recurso y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres se normalizan eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra. En este caso se conserva &amp;lt;code&amp;gt;SMMArrow&amp;lt;/code&amp;gt; tal como está escrito en el nombre del archivo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Destination&amp;lt;/code&amp;gt; elige dónde se muestran los gráficos. Aquí se usa &amp;lt;code&amp;gt;!BG2Line0&amp;lt;/code&amp;gt;; debes colocar en el nivel tiles que utilicen esa zona y asegurarte de que ningún otro recurso la sobrescriba. &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes equivalen a 16 tiles de 8×8 en gráficos de 4 bits por píxel.&lt;br /&gt;
&lt;br /&gt;
El cálculo de este ejemplo está hecho para cuatro imágenes de &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes. Cambiar el tamaño o la cantidad de imágenes requiere ajustar también ese cálculo. Las cuatro imágenes utilizadas deben estar en el mismo banco de origen, porque la transferencia recibe una dirección y un banco por separado.&lt;br /&gt;
&lt;br /&gt;
Si una transferencia normal se rechaza, permanece la imagen anterior y se intenta otra carga en el siguiente cambio de la animación. &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; permite detener la animación junto con el juego. La carga inicial utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; una sola vez; los cambios durante el juego respetan el límite de datos por frame.&lt;br /&gt;
&lt;br /&gt;
== Cambiar paletas durante el juego ==&lt;br /&gt;
&lt;br /&gt;
Al cambiar una paleta hay que distinguir dos casos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Sin efecto global sobre esa paleta:&#039;&#039;&#039; programa la carga a CGRAM y guarda también los colores nuevos en la copia de Dynamic Xtreme y en el buffer de paletas de SMW. Este último es importante: si no lo actualizas, los colores pueden corromperse durante la animación de victoria del goal.&lt;br /&gt;
* &#039;&#039;&#039;Con efecto global sobre esa paleta:&#039;&#039;&#039; actualiza solamente los colores originales que guarda Dynamic Xtreme e invalida sus efectos anteriores. El sistema aplicará el efecto a los colores nuevos antes de cargarlos. No envíes primero la paleta sin efecto a CGRAM, porque se vería sin efecto durante un frame.&lt;br /&gt;
&lt;br /&gt;
El ejemplo siguiente elige entre ambas opciones. Utiliza &amp;lt;code&amp;gt;SMMArrowPal.bin&amp;lt;/code&amp;gt;, un archivo de 15 colores (&amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes), y cambia los colores 1-F de la paleta 7. El color 0 queda sin modificar.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt; puedes declarar los recursos:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
!SMWPaletteBuffer = $0905|!addr&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
if !PalettesEffects&lt;br /&gt;
    ; Comprobar si la paleta 7 recibe un efecto global.&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    AND #$80&lt;br /&gt;
    BEQ .WithoutEffect&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    BEQ .WithoutEffect&lt;br /&gt;
    JMP .WithEffect&lt;br /&gt;
endif&lt;br /&gt;
&lt;br /&gt;
.WithoutEffect&lt;br /&gt;
    ; Programar la carga de los colores sin efecto.&lt;br /&gt;
    %TransferResourceToCGRAM(#$71, &amp;quot;SMMArrowPal&amp;quot;)&lt;br /&gt;
    BCS .CopyDirect&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.CopyDirect&lt;br /&gt;
    REP #$30&lt;br /&gt;
    LDX #$001C&lt;br /&gt;
.CopyDirectColors&lt;br /&gt;
    LDA.l !ResourceSMMArrowPal,x&lt;br /&gt;
    STA.l DX_PPU_CGRAM_PaletteCopy+$00E2,x&lt;br /&gt;
    STA.l !SMWPaletteBuffer+$00E2,x&lt;br /&gt;
    DEX&lt;br /&gt;
    DEX&lt;br /&gt;
    BPL .CopyDirectColors&lt;br /&gt;
    SEP #$30&lt;br /&gt;
    BRA .Invalidate&lt;br /&gt;
&lt;br /&gt;
if !PalettesEffects&lt;br /&gt;
.WithEffect&lt;br /&gt;
    ; Guardar los colores originales, sin cargarlos aún a CGRAM.&lt;br /&gt;
    REP #$30&lt;br /&gt;
    LDX #$001C&lt;br /&gt;
.CopyBaseColors&lt;br /&gt;
    LDA.l !ResourceSMMArrowPal,x&lt;br /&gt;
    STA.l DX_PPU_CGRAM_PaletteCopy+$00E2,x&lt;br /&gt;
    DEX&lt;br /&gt;
    DEX&lt;br /&gt;
    BPL .CopyBaseColors&lt;br /&gt;
    SEP #$30&lt;br /&gt;
endif&lt;br /&gt;
&lt;br /&gt;
.Invalidate&lt;br /&gt;
if !PalettesEffects&lt;br /&gt;
    ; Indicar que el efecto debe calcularse con los colores nuevos.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$FFFF&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_LastGlobalEffectIDPerPal+$0E&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    ; Paleta 7: borrar su bit $80, conservando las demás paletas.&lt;br /&gt;
    LDA.l DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&lt;br /&gt;
    AND #$7F&lt;br /&gt;
    STA.l DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&lt;br /&gt;
    LDA.l DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&lt;br /&gt;
    AND #$7F&lt;br /&gt;
    STA.l DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&lt;br /&gt;
    LDA.l DX_PPU_CGRAM_BGEffectLoaded&lt;br /&gt;
    AND #$7F&lt;br /&gt;
    STA.l DX_PPU_CGRAM_BGEffectLoaded&lt;br /&gt;
endif&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La posición &amp;lt;code&amp;gt;+$00E2&amp;lt;/code&amp;gt; corresponde al color &amp;lt;code&amp;gt;$71&amp;lt;/code&amp;gt;, porque cada color ocupa 2 bytes. &amp;lt;code&amp;gt;!SMWPaletteBuffer&amp;lt;/code&amp;gt; es un nombre definido en este ejemplo para el buffer de SMW; no es un define generado por Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Cuando hay un efecto global, el ejemplo no escribe los colores originales en ese buffer de SMW: el sistema de efectos guardará allí los colores ya procesados al programar su carga. Así se evita mostrar primero la paleta sin efecto.&lt;br /&gt;
&lt;br /&gt;
Después de cambiar los colores se borran los indicadores RGB, HSL y de efecto calculado de la paleta 7. Su último ID de efecto se pone en &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; para que vuelva a procesarse, aunque el efecto seleccionado siga siendo el mismo. Esto también deja preparada una carga sin efecto para recibir uno más adelante. No repitas esta invalidación en cada frame: hazla cuando cambien los colores.&lt;br /&gt;
&lt;br /&gt;
Si utilizas otra paleta, cambia también las posiciones y el bit que se borra. Para las paletas 0-7 se utilizan las variables que empiezan por &amp;lt;code&amp;gt;BG&amp;lt;/code&amp;gt;; para las 8-F, las que empiezan por &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt;. El bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; corresponde a la primera de cada grupo y &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; a la última. Por ejemplo, la paleta 9 usa el bit &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, que se borra con &amp;lt;code&amp;gt;AND #$FD&amp;lt;/code&amp;gt;, y su último ID está en &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal+$12&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceSMMArrowPalSize&amp;lt;/code&amp;gt; se generan al instalar el recurso y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza eliminando separadores y poniendo en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
Para cambiar los colores durante el juego, lleva este código a una rutina llamada desde &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; cuando corresponda. En la carga directa, el carry de la macro indica si se aceptó la transferencia; si no se aceptó, vuelve a intentarlo en otro frame. No hace falta repetir una carga ya aceptada si los colores no van a cambiar.&lt;br /&gt;
&lt;br /&gt;
Si eliges una paleta de sprites 8-F para un uso fijo, resérvala primero como se explica al comienzo del artículo. Para otras formas de transferir colores, consulta [[es/Dynamic_Xtreme_ASM_API#PPU|Transferencias de la API]].&lt;br /&gt;
&lt;br /&gt;
== Cambiar los gráficos del jugador ==&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; habilitado, puedes indicar desde qué archivo se leen los gráficos del jugador. El archivo debe utilizar la misma organización de poses que los gráficos originales de Mario; cambiar la dirección no adapta automáticamente un spritesheet de otro formato.&lt;br /&gt;
&lt;br /&gt;
Registra los gráficos como recurso general. Por ejemplo, con &amp;lt;code&amp;gt;Geno.bin&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Geno.dynamicinfo&amp;lt;/code&amp;gt; juntos:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    Geno.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/Geno.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!ResourceGeno&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!ResourceGeno&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Enable&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGeno&amp;lt;/code&amp;gt; se genera desde el recurso del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores; por ejemplo, &amp;lt;code&amp;gt;my_player&amp;lt;/code&amp;gt; produciría &amp;lt;code&amp;gt;MyPlayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El juego continúa eligiendo las poses del jugador normalmente, pero Dynamic Xtreme lee sus tiles desde el nuevo archivo. Este ejemplo cambia los gráficos, no la paleta ni el comportamiento del personaje.&lt;br /&gt;
&lt;br /&gt;
Para volver a los gráficos habituales, cambia el origen a &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!GFX32Buffer&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!GFX32Buffer&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
También puedes ejecutar estos cambios al pulsar un botón o al entrar en un estado concreto. No es necesario escribir la misma dirección en cada frame si no cambió el personaje.&lt;br /&gt;
&lt;br /&gt;
=== Cambiar también la paleta del jugador ===&lt;br /&gt;
&lt;br /&gt;
El jugador divide sus colores en partes. En los archivos de 15 colores del ejemplo de Geno, los primeros 4 colores visibles se copian al color &amp;lt;code&amp;gt;$82&amp;lt;/code&amp;gt;, mientras la rutina del jugador toma los últimos 10 desde la dirección que indiques. El color intermedio y la disposición del archivo deben coincidir con el formato esperado por el jugador.&lt;br /&gt;
&lt;br /&gt;
Después de declarar &amp;lt;code&amp;gt;GenoPal.bin&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt;, este fragmento configura su paleta. Esta variante es para un jugador que no recibe efectos globales de paleta:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
!SMWPaletteBuffer = $0905|!addr&lt;br /&gt;
&lt;br /&gt;
    ; Colores 2-5 de la paleta 8: omitir el primer color del archivo.&lt;br /&gt;
    %ForcedTransferToCGRAMFromAddr(#$82, !ResourceGenoPal+$02, #$0008)&lt;br /&gt;
&lt;br /&gt;
    ; Colores 6-F: la rutina del jugador los toma desde este origen.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!ResourceGenoPal+$0A&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.b #!ResourceGenoPal&amp;gt;&amp;gt;16&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Enable&lt;br /&gt;
&lt;br /&gt;
    ; Guardar los colores originales y actualizar el buffer de SMW.&lt;br /&gt;
    REP #$30&lt;br /&gt;
    LDX #$001C&lt;br /&gt;
.CopyPlayerColors&lt;br /&gt;
    LDA.l !ResourceGenoPal,x&lt;br /&gt;
    STA.l DX_PPU_CGRAM_PaletteCopy+$0102,x&lt;br /&gt;
    STA.l !SMWPaletteBuffer+$0102,x&lt;br /&gt;
    DEX&lt;br /&gt;
    DEX&lt;br /&gt;
    BPL .CopyPlayerColors&lt;br /&gt;
if !PalettesEffects&lt;br /&gt;
    LDA #$FFFF&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_LastGlobalEffectIDPerPal+$10&lt;br /&gt;
endif&lt;br /&gt;
    SEP #$30&lt;br /&gt;
&lt;br /&gt;
if !PalettesEffects&lt;br /&gt;
    ; Paleta 8: borrar el bit $01 y conservar las demás paletas.&lt;br /&gt;
    LDA.l DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&lt;br /&gt;
    AND #$FE&lt;br /&gt;
    STA.l DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&lt;br /&gt;
    LDA.l DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&lt;br /&gt;
    AND #$FE&lt;br /&gt;
    STA.l DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&lt;br /&gt;
    LDA.l DX_PPU_CGRAM_SPEffectLoaded&lt;br /&gt;
    AND #$FE&lt;br /&gt;
    STA.l DX_PPU_CGRAM_SPEffectLoaded&lt;br /&gt;
endif&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGenoPal&amp;lt;/code&amp;gt; se genera al instalar ese recurso del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre sigue la normalización habitual, conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
El fragmento también actualiza la copia de colores, el buffer de SMW e invalida los efectos anteriores de la paleta 8. Hazlo cuando cambies de paleta, no en cada frame. &amp;lt;code&amp;gt;!SMWPaletteBuffer&amp;lt;/code&amp;gt; es un nombre definido en el ejemplo para el buffer de SMW, no un define generado por Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
No uses esta transferencia directa mientras el jugador reciba un efecto global: también mostraría colores sin efecto durante un frame. En ese caso hay que preparar los colores originales y dejar que el sistema cargue el resultado del efecto, como se explica en el apartado anterior; además, debe respetarse la carga especial de colores del jugador.&lt;br /&gt;
&lt;br /&gt;
Si el personaje utiliza colores distintos para Mario, Luigi o el estado de fuego, selecciona el recurso correspondiente antes de aplicar este cambio. El código de cambio de jugador del paquete utiliza una tabla de cuatro paletas para esa selección.&lt;br /&gt;
&lt;br /&gt;
== Aplicar un efecto global de paleta ==&lt;br /&gt;
&lt;br /&gt;
Un efecto global permite cambiar los colores de varias paletas con una sola selección. Primero defines el efecto en un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y después indicas desde UberASM qué paletas lo reciben.&lt;br /&gt;
&lt;br /&gt;
=== Preparar el efecto ===&lt;br /&gt;
&lt;br /&gt;
Este ejemplo elimina la saturación de los colores, utilizando &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt;. Guarda lo siguiente como &amp;lt;code&amp;gt;DynamicXtreme/DecreaseSaturation.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;Channel2&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;Ratio2&amp;quot;: 127,&lt;br /&gt;
      &amp;quot;EffectType&amp;quot;: 11&lt;br /&gt;
    }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Channel2 = 0&amp;lt;/code&amp;gt; indica la saturación a la que se quiere llegar y &amp;lt;code&amp;gt;Ratio2 = 127&amp;lt;/code&amp;gt; aplica el cambio completo. Los valores de color siguen estando entre 0 y 31; los ratios utilizan 0-127.&lt;br /&gt;
&lt;br /&gt;
Si adaptas un efecto antiguo cuyos ratios iban de 0 a 31, conserva la proporción del cambio: 0 sigue siendo 0, 31 pasa a 127 y un valor intermedio se convierte aproximadamente con &amp;lt;code&amp;gt;ratio antiguo × 127 ÷ 31&amp;lt;/code&amp;gt;, redondeando al entero más cercano. No multipliques los valores &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt;: siguen usando 0-31. Los archivos antiguos que utilizan &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; también deben indicar el &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; actual; por ejemplo, &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt; es 9, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; es 11 y &amp;lt;code&amp;gt;MixRG&amp;lt;/code&amp;gt; es 2.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo se genera &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation0&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El número final es el índice del efecto dentro del archivo, no su ratio. Los nombres se normalizan eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;decrease_saturation&amp;lt;/code&amp;gt; produciría &amp;lt;code&amp;gt;DecreaseSaturation&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Elegir las paletas afectadas ===&lt;br /&gt;
&lt;br /&gt;
Cada bit de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; permite el efecto en una paleta 0-7; &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; hace lo mismo para las paletas 8-F:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor del bit !! Paleta de fondo !! Paleta de sprites&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || 0 || 8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || 1 || 9&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || 2 || A&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || 3 || B&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || 4 || C&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || 5 || D&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || 6 || E&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; || 7 || F&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Puedes combinar bits para elegir varias. Por ejemplo, &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; selecciona las dos primeras y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; selecciona las ocho. En sprites con asignación dinámica, configura también el bit E de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; según quieras que su paleta participe en el efecto global.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto fijo ===&lt;br /&gt;
&lt;br /&gt;
El siguiente código aplica el efecto a las paletas de fondo 0-7. La máscara de sprites se deja en 0:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/DecreaseSaturation.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$FF&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDDecreaseSaturation0&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
No necesitas repetir la selección en &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; mientras quieras mantener el mismo efecto. Dynamic Xtreme procesa los colores de las paletas habilitadas.&lt;br /&gt;
&lt;br /&gt;
Para quitar el efecto, escribe 0 en el ID global y deja que el sistema procese las paletas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Incluir el color fijo o el color 0,0 ===&lt;br /&gt;
&lt;br /&gt;
Estos dos colores se controlan mediante &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt;. El bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; permite el efecto en el color fijo y &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; en el color 0,0. Para habilitar ambos, utiliza &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para incluir el color fijo sin cambiar la opción del color 0,0:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    LDA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
    ORA #$01&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hacer que el efecto se repita en un ciclo ===&lt;br /&gt;
&lt;br /&gt;
Para animar un efecto, prepara varios efectos consecutivos dentro del mismo archivo y ve cambiando el ID seleccionado. Este ejemplo utiliza cuatro tonos HSL con el cambio aplicado al máximo. Guarda el archivo como &amp;lt;code&amp;gt;DynamicXtreme/Hue.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0,  &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 8,  &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 16, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 24, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, los defines &amp;lt;code&amp;gt;!PaletteEffectIDHue0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDHue3&amp;lt;/code&amp;gt; quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre procede del archivo y utiliza la normalización habitual en PascalCase.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Hue.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$FF&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDHue0&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $9D&lt;br /&gt;
    ORA $13D4|!addr&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$07&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!PaletteEffectIDHue3&lt;br /&gt;
    BCS .Restart&lt;br /&gt;
    INC A&lt;br /&gt;
    BRA .Store&lt;br /&gt;
.Restart&lt;br /&gt;
    LDA #!PaletteEffectIDHue0&lt;br /&gt;
.Store&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El código mantiene cada efecto durante ocho frames y vuelve al primero después de mostrar el último. Puedes añadir más pasos al archivo y cambiar el define del último efecto para obtener una animación más suave.&lt;br /&gt;
&lt;br /&gt;
=== Hacer una transición que se detiene al terminar ===&lt;br /&gt;
&lt;br /&gt;
Para cambiar poco a poco los colores y conservar el resultado final, utiliza una secuencia como esta. El ejemplo reduce el rojo y el verde para dar un aspecto azulado al nivel. Guarda el archivo como &amp;lt;code&amp;gt;DynamicXtreme/Night.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 0,   &amp;quot;Ratio2&amp;quot;: 0,   &amp;quot;EffectType&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 42,  &amp;quot;Ratio2&amp;quot;: 42,  &amp;quot;EffectType&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 85,  &amp;quot;Ratio2&amp;quot;: 85,  &amp;quot;EffectType&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 2 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Selecciona &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;, con las máscaras de paleta del ejemplo anterior. Para avanzar y detenerte al llegar al último, utiliza este &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Night.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $9D&lt;br /&gt;
    ORA $13D4|!addr&lt;br /&gt;
    BNE .Return&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$07&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!PaletteEffectIDNight3&lt;br /&gt;
    BCS .Done&lt;br /&gt;
    INC A&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
.Done&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDNight3&amp;lt;/code&amp;gt; se generan desde &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres siguen la normalización en PascalCase. Este código avanza por los efectos de mezcla del archivo; para una transición hacia otra paleta completa, utiliza un efecto &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt;, explicado en [[es/Dynamic_Xtreme_files_and_formats#Transiciones_de_paleta|Archivos y formatos]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21356</id>
		<title>es/Dynamic Xtreme UberASM guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21356"/>
		<updated>2026-10-24T05:58:09Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_UberASM_guide}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo utilizar Dynamic Xtreme desde UberASM para configurar los recursos de un nivel y crear cambios de gráficos y colores durante el juego. Se incluyen ejemplos para reservar paletas, elegir el espacio disponible para sprites dinámicos, crear animaciones y modificar los gráficos del jugador.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Tener UberASMTool instalado y configurado para insertar códigos en tu ROM.&lt;br /&gt;
* Tener Dynamic Xtreme instalado con las funciones necesarias para el ejemplo que quieras utilizar. Consulta la [[es/Dynamic_Xtreme_Quick_Start|guía de inicio rápido]] para su instalación.&lt;br /&gt;
&lt;br /&gt;
Para consultar los parámetros de una llamada o el uso de una variable, utiliza la [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]].&lt;br /&gt;
&lt;br /&gt;
== Preparar los ejemplos ==&lt;br /&gt;
&lt;br /&gt;
Cada ejemplo es independiente. Guarda el código de nivel en la carpeta correspondiente de UberASMTool y añádelo a su lista. Si reúnes varios ejemplos en un archivo, combina sus bloques &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; para no repetir las mismas etiquetas.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt; prepara datos durante la carga del nivel. Se utiliza aquí para reservar paletas antes de que las reclamen los sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; prepara las opciones al entrar al nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; ejecuta el código durante el juego, una vez por frame.&lt;br /&gt;
&lt;br /&gt;
Los defines y macros de Dynamic Xtreme deben estar disponibles en UberASMTool mediante la integración realizada durante la instalación. Si utilizas gráficos, paletas o efectos adicionales, decláralos en el ASM mediante los includes correspondientes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MyResources.dynamicinfo&amp;quot;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/MyEffect.paleffect&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las rutas son relativas al ASM. Incluye únicamente los archivos que utiliza tu ejemplo. También puedes usar las carpetas tradicionales de Dynamic Xtreme, como se explica en [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
&lt;br /&gt;
Después de añadir o modificar estos recursos, instala primero Dynamic Xtreme y después UberASMTool. Si solo cambias la lógica del ASM, basta con volver a ejecutar UberASMTool.&lt;br /&gt;
&lt;br /&gt;
== Reservar paletas para otros recursos ==&lt;br /&gt;
&lt;br /&gt;
Si una animación, un HUD u otro recurso necesita una paleta fija, conviene reservarla para que Dynamic Xtreme no la elija al asignar colores a los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
Para reservarla, escribe &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; en su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt;. Cada entrada ocupa 2 bytes. Por ejemplo, la paleta 9 utiliza el desplazamiento &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;: 9 × 2.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
load:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$FFFE&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_ID+$12    ; Reservar la paleta 9&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para reservar varias, escribe el mismo valor en sus entradas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Paleta !! Desplazamiento&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| A || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| B || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| C || &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| D || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| E || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| F || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La reserva impide que la asignación automática reclame esa paleta; no carga colores por sí misma. Un recurso configurado para utilizarla manualmente todavía puede cambiar sus colores, por lo que no debes asignársela también a otro recurso que necesite una paleta diferente.&lt;br /&gt;
&lt;br /&gt;
== Elegir el espacio de VRAM para sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Los sprites dinámicos necesitan una parte de VRAM donde cargar sus poses. Elige un espacio que no estés utilizando para gráficos fijos del nivel.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para permitir que utilicen SP4:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si necesitas más espacio y el nivel lo permite, puedes elegir &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; para SP3 y SP4, o &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt; para SP2, SP3 y SP4. Hay más opciones, incluidas medias páginas y configuraciones para compartir espacio con el jugador o DSX.&lt;br /&gt;
&lt;br /&gt;
Los defines disponibles están en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y en la [[es/Dynamic_Xtreme_ASM_API#Configuraciones_de_espacio_para_poses_dinámicas|tabla de configuraciones de la API]]. Configura el espacio antes de que el nivel empiece a cargar poses; cambiarlo no elimina automáticamente las poses que ya estaban en VRAM.&lt;br /&gt;
&lt;br /&gt;
== Configurar la cantidad de datos que se transfieren por frame ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; indica cuántos bytes pueden programar las cargas normales de Dynamic Xtreme durante un frame. Lo comparten las poses dinámicas, las animaciones y las demás transferencias realizadas con sus macros.&lt;br /&gt;
&lt;br /&gt;
El valor predeterminado es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Este ejemplo lo aumenta a &amp;lt;code&amp;gt;$0A00&amp;lt;/code&amp;gt;, equivalente a 2560 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0A00&lt;br /&gt;
    STA.l DX_Dynamic_MaxDataPerFrame&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Subirlo permite intentar más cargas durante el mismo frame, pero no aumenta el tiempo que tiene SNES para copiarlas. Si la cantidad total es excesiva, pueden aparecer problemas visuales. Ajusta el valor según el nivel y comprueba el resultado con sus sprites y animaciones funcionando juntos.&lt;br /&gt;
&lt;br /&gt;
Las macros normales devuelven el carry desactivado si una carga no cabe en el límite. En ese caso, conserva lo que ya se muestra y vuelve a intentarlo después. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; se saltan la comprobación y también suman sus bytes al total.&lt;br /&gt;
&lt;br /&gt;
== Crear animaciones de gráficos ==&lt;br /&gt;
&lt;br /&gt;
Una animación de tiles se consigue copiando distintas imágenes al mismo lugar de VRAM. Los tiles del nivel siguen apuntando al mismo lugar, pero los gráficos que contienen van cambiando.&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las primeras cuatro imágenes de &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;, con &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes por imagen, y cambia de imagen cada ocho frames. El archivo se registra como recurso general, no como pose de sprite dinámico.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;, junto a &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ASM del nivel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
!AnimationGraphics = !ResourceSMMArrow&lt;br /&gt;
!Destination = !BG2Line0&lt;br /&gt;
!BytesPerFrame = $0200&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    %ForcedTransferToVRAMFromAddr(#!Destination, !AnimationGraphics, #!BytesPerFrame)&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $9D&lt;br /&gt;
    ORA $13D4|!addr&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    ; Cambiar de imagen cada ocho frames.&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$07&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    ; Obtener 0, $0200, $0400 o $0600 como desplazamiento en el archivo.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$0018&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC.w #!AnimationGraphics&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    %TransferToVRAM(#!Destination, $00, #(!AnimationGraphics&amp;gt;&amp;gt;16), #!BytesPerFrame)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt; es la dirección que se genera al instalar el recurso y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres se normalizan eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra. En este caso se conserva &amp;lt;code&amp;gt;SMMArrow&amp;lt;/code&amp;gt; tal como está escrito en el nombre del archivo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Destination&amp;lt;/code&amp;gt; elige dónde se muestran los gráficos. Aquí se usa &amp;lt;code&amp;gt;!BG2Line0&amp;lt;/code&amp;gt;; debes colocar en el nivel tiles que utilicen esa zona y asegurarte de que ningún otro recurso la sobrescriba. &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes equivalen a 16 tiles de 8×8 en gráficos de 4 bits por píxel.&lt;br /&gt;
&lt;br /&gt;
El cálculo de este ejemplo está hecho para cuatro imágenes de &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes. Cambiar el tamaño o la cantidad de imágenes requiere ajustar también ese cálculo. Las cuatro imágenes utilizadas deben estar en el mismo banco de origen, porque la transferencia recibe una dirección y un banco por separado.&lt;br /&gt;
&lt;br /&gt;
Si una transferencia normal se rechaza, permanece la imagen anterior y se intenta otra carga en el siguiente cambio de la animación. &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; permite detener la animación junto con el juego. La carga inicial utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; una sola vez; los cambios durante el juego respetan el límite de datos por frame.&lt;br /&gt;
&lt;br /&gt;
== Cambiar paletas durante el juego ==&lt;br /&gt;
&lt;br /&gt;
Al cambiar una paleta hay que distinguir dos casos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Sin efecto global sobre esa paleta:&#039;&#039;&#039; programa la carga a CGRAM y guarda también los colores nuevos en la copia de Dynamic Xtreme y en el buffer de paletas de SMW. Este último es importante: si no lo actualizas, los colores pueden corromperse durante la animación de victoria del goal.&lt;br /&gt;
* &#039;&#039;&#039;Con efecto global sobre esa paleta:&#039;&#039;&#039; actualiza solamente los colores originales que guarda Dynamic Xtreme e invalida sus efectos anteriores. El sistema aplicará el efecto a los colores nuevos antes de cargarlos. No envíes primero la paleta sin efecto a CGRAM, porque se vería sin efecto durante un frame.&lt;br /&gt;
&lt;br /&gt;
El ejemplo siguiente elige entre ambas opciones. Utiliza &amp;lt;code&amp;gt;SMMArrowPal.bin&amp;lt;/code&amp;gt;, un archivo de 15 colores (&amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes), y cambia los colores 1-F de la paleta 7. El color 0 queda sin modificar.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt; puedes declarar los recursos:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
!SMWPaletteBuffer = $0905|!addr&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
if !PalettesEffects&lt;br /&gt;
    ; Comprobar si la paleta 7 recibe un efecto global.&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    AND #$80&lt;br /&gt;
    BEQ .WithoutEffect&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    BEQ .WithoutEffect&lt;br /&gt;
    JMP .WithEffect&lt;br /&gt;
endif&lt;br /&gt;
&lt;br /&gt;
.WithoutEffect&lt;br /&gt;
    ; Programar la carga de los colores sin efecto.&lt;br /&gt;
    %TransferResourceToCGRAM(#$71, &amp;quot;SMMArrowPal&amp;quot;)&lt;br /&gt;
    BCS .CopyDirect&lt;br /&gt;
    RTL&lt;br /&gt;
&lt;br /&gt;
.CopyDirect&lt;br /&gt;
    REP #$30&lt;br /&gt;
    LDX #$001C&lt;br /&gt;
.CopyDirectColors&lt;br /&gt;
    LDA.l !ResourceSMMArrowPal,x&lt;br /&gt;
    STA.l DX_PPU_CGRAM_PaletteCopy+$00E2,x&lt;br /&gt;
    STA.l !SMWPaletteBuffer+$00E2,x&lt;br /&gt;
    DEX&lt;br /&gt;
    DEX&lt;br /&gt;
    BPL .CopyDirectColors&lt;br /&gt;
    SEP #$30&lt;br /&gt;
    BRA .Invalidate&lt;br /&gt;
&lt;br /&gt;
if !PalettesEffects&lt;br /&gt;
.WithEffect&lt;br /&gt;
    ; Guardar los colores originales, sin cargarlos aún a CGRAM.&lt;br /&gt;
    REP #$30&lt;br /&gt;
    LDX #$001C&lt;br /&gt;
.CopyBaseColors&lt;br /&gt;
    LDA.l !ResourceSMMArrowPal,x&lt;br /&gt;
    STA.l DX_PPU_CGRAM_PaletteCopy+$00E2,x&lt;br /&gt;
    DEX&lt;br /&gt;
    DEX&lt;br /&gt;
    BPL .CopyBaseColors&lt;br /&gt;
    SEP #$30&lt;br /&gt;
endif&lt;br /&gt;
&lt;br /&gt;
.Invalidate&lt;br /&gt;
if !PalettesEffects&lt;br /&gt;
    ; Indicar que el efecto debe calcularse con los colores nuevos.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$FFFF&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_LastGlobalEffectIDPerPal+$0E&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    ; Paleta 7: borrar su bit $80, conservando las demás paletas.&lt;br /&gt;
    LDA.l DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&lt;br /&gt;
    AND #$7F&lt;br /&gt;
    STA.l DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&lt;br /&gt;
    LDA.l DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&lt;br /&gt;
    AND #$7F&lt;br /&gt;
    STA.l DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&lt;br /&gt;
    LDA.l DX_PPU_CGRAM_BGEffectLoaded&lt;br /&gt;
    AND #$7F&lt;br /&gt;
    STA.l DX_PPU_CGRAM_BGEffectLoaded&lt;br /&gt;
endif&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La posición &amp;lt;code&amp;gt;+$00E2&amp;lt;/code&amp;gt; corresponde al color &amp;lt;code&amp;gt;$71&amp;lt;/code&amp;gt;, porque cada color ocupa 2 bytes. &amp;lt;code&amp;gt;!SMWPaletteBuffer&amp;lt;/code&amp;gt; es un nombre definido en este ejemplo para el buffer de SMW; no es un define generado por Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
Cuando hay un efecto global, el ejemplo no escribe los colores originales en ese buffer de SMW: el sistema de efectos guardará allí los colores ya procesados al programar su carga. Así se evita mostrar primero la paleta sin efecto.&lt;br /&gt;
&lt;br /&gt;
Después de cambiar los colores se borran los indicadores RGB, HSL y de efecto calculado de la paleta 7. Su último ID de efecto se pone en &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; para que vuelva a procesarse, aunque el efecto seleccionado siga siendo el mismo. Esto también deja preparada una carga sin efecto para recibir uno más adelante. No repitas esta invalidación en cada frame: hazla cuando cambien los colores.&lt;br /&gt;
&lt;br /&gt;
Si utilizas otra paleta, cambia también las posiciones y el bit que se borra. Para las paletas 0-7 se utilizan las variables que empiezan por &amp;lt;code&amp;gt;BG&amp;lt;/code&amp;gt;; para las 8-F, las que empiezan por &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt;. El bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; corresponde a la primera de cada grupo y &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; a la última. Por ejemplo, la paleta 9 usa el bit &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, que se borra con &amp;lt;code&amp;gt;AND #$FD&amp;lt;/code&amp;gt;, y su último ID está en &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal+$12&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceSMMArrowPalSize&amp;lt;/code&amp;gt; se generan al instalar el recurso y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza eliminando separadores y poniendo en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
Para cambiar los colores durante el juego, lleva este código a una rutina llamada desde &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; cuando corresponda. En la carga directa, el carry de la macro indica si se aceptó la transferencia; si no se aceptó, vuelve a intentarlo en otro frame. No hace falta repetir una carga ya aceptada si los colores no van a cambiar.&lt;br /&gt;
&lt;br /&gt;
Si eliges una paleta de sprites 8-F para un uso fijo, resérvala primero como se explica al comienzo del artículo. Para otras formas de transferir colores, consulta [[es/Dynamic_Xtreme_ASM_API#PPU|Transferencias de la API]].&lt;br /&gt;
&lt;br /&gt;
== Cambiar los gráficos del jugador ==&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; habilitado, puedes indicar desde qué archivo se leen los gráficos del jugador. El archivo debe utilizar la misma organización de poses que los gráficos originales de Mario; cambiar la dirección no adapta automáticamente un spritesheet de otro formato.&lt;br /&gt;
&lt;br /&gt;
Registra los gráficos como recurso general. Por ejemplo, con &amp;lt;code&amp;gt;Geno.bin&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Geno.dynamicinfo&amp;lt;/code&amp;gt; juntos:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    Geno.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/Geno.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!ResourceGeno&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!ResourceGeno&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Enable&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGeno&amp;lt;/code&amp;gt; se genera desde el recurso del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores; por ejemplo, &amp;lt;code&amp;gt;my_player&amp;lt;/code&amp;gt; produciría &amp;lt;code&amp;gt;MyPlayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El juego continúa eligiendo las poses del jugador normalmente, pero Dynamic Xtreme lee sus tiles desde el nuevo archivo. Este ejemplo cambia los gráficos, no la paleta ni el comportamiento del personaje.&lt;br /&gt;
&lt;br /&gt;
Para volver a los gráficos habituales, cambia el origen a &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!GFX32Buffer&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!GFX32Buffer&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
También puedes ejecutar estos cambios al pulsar un botón o al entrar en un estado concreto. No es necesario escribir la misma dirección en cada frame si no cambió el personaje.&lt;br /&gt;
&lt;br /&gt;
=== Cambiar también la paleta del jugador ===&lt;br /&gt;
&lt;br /&gt;
El jugador divide sus colores en partes. En los archivos de 15 colores del ejemplo de Geno, los primeros 4 colores visibles se copian al color &amp;lt;code&amp;gt;$82&amp;lt;/code&amp;gt;, mientras la rutina del jugador toma los últimos 10 desde la dirección que indiques. El color intermedio y la disposición del archivo deben coincidir con el formato esperado por el jugador.&lt;br /&gt;
&lt;br /&gt;
Después de declarar &amp;lt;code&amp;gt;GenoPal.bin&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt;, este fragmento configura su paleta. Esta variante es para un jugador que no recibe efectos globales de paleta:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
!SMWPaletteBuffer = $0905|!addr&lt;br /&gt;
&lt;br /&gt;
    ; Colores 2-5 de la paleta 8: omitir el primer color del archivo.&lt;br /&gt;
    %ForcedTransferToCGRAMFromAddr(#$82, !ResourceGenoPal+$02, #$0008)&lt;br /&gt;
&lt;br /&gt;
    ; Colores 6-F: la rutina del jugador los toma desde este origen.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!ResourceGenoPal+$0A&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.b #!ResourceGenoPal&amp;gt;&amp;gt;16&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Enable&lt;br /&gt;
&lt;br /&gt;
    ; Guardar los colores originales y actualizar el buffer de SMW.&lt;br /&gt;
    REP #$30&lt;br /&gt;
    LDX #$001C&lt;br /&gt;
.CopyPlayerColors&lt;br /&gt;
    LDA.l !ResourceGenoPal,x&lt;br /&gt;
    STA.l DX_PPU_CGRAM_PaletteCopy+$0102,x&lt;br /&gt;
    STA.l !SMWPaletteBuffer+$0102,x&lt;br /&gt;
    DEX&lt;br /&gt;
    DEX&lt;br /&gt;
    BPL .CopyPlayerColors&lt;br /&gt;
if !PalettesEffects&lt;br /&gt;
    LDA #$FFFF&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_LastGlobalEffectIDPerPal+$10&lt;br /&gt;
endif&lt;br /&gt;
    SEP #$30&lt;br /&gt;
&lt;br /&gt;
if !PalettesEffects&lt;br /&gt;
    ; Paleta 8: borrar el bit $01 y conservar las demás paletas.&lt;br /&gt;
    LDA.l DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&lt;br /&gt;
    AND #$FE&lt;br /&gt;
    STA.l DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&lt;br /&gt;
    LDA.l DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&lt;br /&gt;
    AND #$FE&lt;br /&gt;
    STA.l DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&lt;br /&gt;
    LDA.l DX_PPU_CGRAM_SPEffectLoaded&lt;br /&gt;
    AND #$FE&lt;br /&gt;
    STA.l DX_PPU_CGRAM_SPEffectLoaded&lt;br /&gt;
endif&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGenoPal&amp;lt;/code&amp;gt; se genera al instalar ese recurso del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre sigue la normalización habitual, conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
El fragmento también actualiza la copia de colores, el buffer de SMW e invalida los efectos anteriores de la paleta 8. Hazlo cuando cambies de paleta, no en cada frame. &amp;lt;code&amp;gt;!SMWPaletteBuffer&amp;lt;/code&amp;gt; es un nombre definido en el ejemplo para el buffer de SMW, no un define generado por Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
No uses esta transferencia directa mientras el jugador reciba un efecto global: también mostraría colores sin efecto durante un frame. En ese caso hay que preparar los colores originales y dejar que el sistema cargue el resultado del efecto, como se explica en el apartado anterior; además, debe respetarse la carga especial de colores del jugador.&lt;br /&gt;
&lt;br /&gt;
Si el personaje utiliza colores distintos para Mario, Luigi o el estado de fuego, selecciona el recurso correspondiente antes de aplicar este cambio. El código de cambio de jugador del paquete utiliza una tabla de cuatro paletas para esa selección.&lt;br /&gt;
&lt;br /&gt;
== Aplicar un efecto global de paleta ==&lt;br /&gt;
&lt;br /&gt;
Un efecto global permite cambiar los colores de varias paletas con una sola selección. Primero defines el efecto en un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y después indicas desde UberASM qué paletas lo reciben.&lt;br /&gt;
&lt;br /&gt;
=== Preparar el efecto ===&lt;br /&gt;
&lt;br /&gt;
Este ejemplo elimina la saturación de los colores, utilizando &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt;. Guarda lo siguiente como &amp;lt;code&amp;gt;DynamicXtreme/DecreaseSaturation.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;Channel2&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;Ratio2&amp;quot;: 127,&lt;br /&gt;
      &amp;quot;EffectType&amp;quot;: 11&lt;br /&gt;
    }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Channel2 = 0&amp;lt;/code&amp;gt; indica la saturación a la que se quiere llegar y &amp;lt;code&amp;gt;Ratio2 = 127&amp;lt;/code&amp;gt; aplica el cambio completo. Los valores de color siguen estando entre 0 y 31; los ratios utilizan 0-127.&lt;br /&gt;
&lt;br /&gt;
Si adaptas un efecto antiguo cuyos ratios iban de 0 a 31, conserva la proporción del cambio: 0 sigue siendo 0, 31 pasa a 127 y un valor intermedio se convierte aproximadamente con &amp;lt;code&amp;gt;ratio antiguo × 127 ÷ 31&amp;lt;/code&amp;gt;, redondeando al entero más cercano. No multipliques los valores &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt;: siguen usando 0-31. Los archivos antiguos que utilizan &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; también deben indicar el &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; actual; por ejemplo, &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt; es 9, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; es 11 y &amp;lt;code&amp;gt;MixRG&amp;lt;/code&amp;gt; es 2.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo se genera &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation0&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El número final es el índice del efecto dentro del archivo, no su ratio. Los nombres se normalizan eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;decrease_saturation&amp;lt;/code&amp;gt; produciría &amp;lt;code&amp;gt;DecreaseSaturation&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Elegir las paletas afectadas ===&lt;br /&gt;
&lt;br /&gt;
Cada bit de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; permite el efecto en una paleta 0-7; &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; hace lo mismo para las paletas 8-F:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor del bit !! Paleta de fondo !! Paleta de sprites&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || 0 || 8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || 1 || 9&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || 2 || A&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || 3 || B&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || 4 || C&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || 5 || D&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || 6 || E&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; || 7 || F&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Puedes combinar bits para elegir varias. Por ejemplo, &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; selecciona las dos primeras y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; selecciona las ocho. En sprites con asignación dinámica, configura también el bit E de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; según quieras que su paleta participe en el efecto global.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto fijo ===&lt;br /&gt;
&lt;br /&gt;
El siguiente código aplica el efecto a las paletas de fondo 0-7. La máscara de sprites se deja en 0:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/DecreaseSaturation.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$FF&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDDecreaseSaturation0&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
No necesitas repetir la selección en &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; mientras quieras mantener el mismo efecto. Dynamic Xtreme procesa los colores de las paletas habilitadas.&lt;br /&gt;
&lt;br /&gt;
Para quitar el efecto, escribe 0 en el ID global y deja que el sistema procese las paletas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Incluir el color fijo o el color 0,0 ===&lt;br /&gt;
&lt;br /&gt;
Estos dos colores se controlan mediante &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt;. El bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; permite el efecto en el color fijo y &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; en el color 0,0. Para habilitar ambos, utiliza &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para incluir el color fijo sin cambiar la opción del color 0,0:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    LDA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
    ORA #$01&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hacer que el efecto se repita en un ciclo ===&lt;br /&gt;
&lt;br /&gt;
Para animar un efecto, prepara varios efectos consecutivos dentro del mismo archivo y ve cambiando el ID seleccionado. Este ejemplo utiliza cuatro tonos HSL con el cambio aplicado al máximo. Guarda el archivo como &amp;lt;code&amp;gt;DynamicXtreme/Hue.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0,  &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 8,  &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 16, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 24, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, los defines &amp;lt;code&amp;gt;!PaletteEffectIDHue0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDHue3&amp;lt;/code&amp;gt; quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre procede del archivo y utiliza la normalización habitual en PascalCase.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Hue.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$FF&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDHue0&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $9D&lt;br /&gt;
    ORA $13D4|!addr&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$07&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!PaletteEffectIDHue3&lt;br /&gt;
    BCS .Restart&lt;br /&gt;
    INC A&lt;br /&gt;
    BRA .Store&lt;br /&gt;
.Restart&lt;br /&gt;
    LDA #!PaletteEffectIDHue0&lt;br /&gt;
.Store&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El código mantiene cada efecto durante ocho frames y vuelve al primero después de mostrar el último. Puedes añadir más pasos al archivo y cambiar el define del último efecto para obtener una animación más suave.&lt;br /&gt;
&lt;br /&gt;
=== Hacer una transición que se detiene al terminar ===&lt;br /&gt;
&lt;br /&gt;
Para cambiar poco a poco los colores y conservar el resultado final, utiliza una secuencia como esta. El ejemplo reduce el rojo y el verde para dar un aspecto azulado al nivel. Guarda el archivo como &amp;lt;code&amp;gt;DynamicXtreme/Night.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 0,   &amp;quot;Ratio2&amp;quot;: 0,   &amp;quot;EffectType&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 42,  &amp;quot;Ratio2&amp;quot;: 42,  &amp;quot;EffectType&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 85,  &amp;quot;Ratio2&amp;quot;: 85,  &amp;quot;EffectType&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 2 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Selecciona &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;, con las máscaras de paleta del ejemplo anterior. Para avanzar y detenerte al llegar al último, utiliza este &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Night.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $9D&lt;br /&gt;
    ORA $13D4|!addr&lt;br /&gt;
    BNE .Return&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$07&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!PaletteEffectIDNight3&lt;br /&gt;
    BCS .Done&lt;br /&gt;
    INC A&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
.Done&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDNight3&amp;lt;/code&amp;gt; se generan desde &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres siguen la normalización en PascalCase. Este código avanza por los efectos de mezcla del archivo; para una transición hacia otra paleta completa, utiliza un efecto &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt;, explicado en [[es/Dynamic_Xtreme_files_and_formats#Transiciones_de_paleta|Archivos y formatos]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21355</id>
		<title>es/Dynamic Xtreme UberASM guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_UberASM_guide&amp;diff=21355"/>
		<updated>2026-10-24T05:36:35Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: Created page with &amp;quot;{{Select Language|Dynamic_Xtreme_UberASM_guide}}  En este artículo se explica cómo utilizar Dynamic Xtreme desde UberASM para configurar los recursos de un nivel y crear cambios de gráficos y colores durante el juego. Se incluyen ejemplos para reservar paletas, elegir el espacio disponible para sprites dinámicos, crear animaciones y modificar los gráficos del jugador.  == Requisitos ==  * Tener UberASMTool instalado y configurado para insertar códigos en tu ROM. *...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_UberASM_guide}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explica cómo utilizar Dynamic Xtreme desde UberASM para configurar los recursos de un nivel y crear cambios de gráficos y colores durante el juego. Se incluyen ejemplos para reservar paletas, elegir el espacio disponible para sprites dinámicos, crear animaciones y modificar los gráficos del jugador.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Tener UberASMTool instalado y configurado para insertar códigos en tu ROM.&lt;br /&gt;
* Tener Dynamic Xtreme instalado con las funciones necesarias para el ejemplo que quieras utilizar. Consulta la [[es/Dynamic_Xtreme_Quick_Start|guía de inicio rápido]] para su instalación.&lt;br /&gt;
&lt;br /&gt;
Para consultar los parámetros de una llamada o el uso de una variable, utiliza la [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]].&lt;br /&gt;
&lt;br /&gt;
== Preparar los ejemplos ==&lt;br /&gt;
&lt;br /&gt;
Cada ejemplo es independiente. Guarda el código de nivel en la carpeta correspondiente de UberASMTool y añádelo a su lista. Si reúnes varios ejemplos en un archivo, combina sus bloques &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; para no repetir las mismas etiquetas.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;load&amp;lt;/code&amp;gt; prepara datos durante la carga del nivel. Se utiliza aquí para reservar paletas antes de que las reclamen los sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; prepara las opciones al entrar al nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; ejecuta el código durante el juego, una vez por frame.&lt;br /&gt;
&lt;br /&gt;
Los defines y macros de Dynamic Xtreme deben estar disponibles en UberASMTool mediante la integración realizada durante la instalación. Si utilizas gráficos, paletas o efectos adicionales, decláralos en el ASM mediante los includes correspondientes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MyResources.dynamicinfo&amp;quot;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/MyEffect.paleffect&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las rutas son relativas al ASM. Incluye únicamente los archivos que utiliza tu ejemplo. También puedes usar las carpetas tradicionales de Dynamic Xtreme, como se explica en [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos]].&lt;br /&gt;
&lt;br /&gt;
Después de añadir o modificar estos recursos, instala primero Dynamic Xtreme y después UberASMTool. Si solo cambias la lógica del ASM, basta con volver a ejecutar UberASMTool.&lt;br /&gt;
&lt;br /&gt;
== Reservar paletas para otros recursos ==&lt;br /&gt;
&lt;br /&gt;
Si una animación, un HUD u otro recurso necesita una paleta fija, conviene reservarla para que Dynamic Xtreme no la elija al asignar colores a los sprites dinámicos.&lt;br /&gt;
&lt;br /&gt;
Para reservarla, escribe &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; en su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt;. Cada entrada ocupa 2 bytes. Por ejemplo, la paleta 9 utiliza el desplazamiento &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;: 9 × 2.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
load:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$FFFE&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_ID+$12    ; Reservar la paleta 9&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para reservar varias, escribe el mismo valor en sus entradas:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Paleta !! Desplazamiento&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| A || &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| B || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| C || &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| D || &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| E || &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| F || &amp;lt;code&amp;gt;$1E&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La reserva impide que la asignación automática reclame esa paleta; no carga colores por sí misma. Un recurso configurado para utilizarla manualmente todavía puede cambiar sus colores, por lo que no debes asignársela también a otro recurso que necesite una paleta diferente.&lt;br /&gt;
&lt;br /&gt;
== Elegir el espacio de VRAM para sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Los sprites dinámicos necesitan una parte de VRAM donde cargar sus poses. Elige un espacio que no estés utilizando para gráficos fijos del nivel.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para permitir que utilicen SP4:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Si necesitas más espacio y el nivel lo permite, puedes elegir &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; para SP3 y SP4, o &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt; para SP2, SP3 y SP4. Hay más opciones, incluidas medias páginas y configuraciones para compartir espacio con el jugador o DSX.&lt;br /&gt;
&lt;br /&gt;
Los defines disponibles están en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y en la [[es/Dynamic_Xtreme_ASM_API#Configuraciones_de_espacio_para_poses_dinámicas|tabla de configuraciones de la API]]. Configura el espacio antes de que el nivel empiece a cargar poses; cambiarlo no elimina automáticamente las poses que ya estaban en VRAM.&lt;br /&gt;
&lt;br /&gt;
== Configurar la cantidad de datos que se transfieren por frame ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; indica cuántos bytes pueden programar las cargas normales de Dynamic Xtreme durante un frame. Lo comparten las poses dinámicas, las animaciones y las demás transferencias realizadas con sus macros.&lt;br /&gt;
&lt;br /&gt;
El valor inicial es &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt;, equivalente a 2048 bytes. Para establecerlo desde UberASM:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0800&lt;br /&gt;
    STA.l DX_Dynamic_MaxDataPerFrame&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Subirlo permite intentar más cargas durante el mismo frame, pero no aumenta el tiempo que tiene SNES para copiarlas. Si la cantidad total es excesiva, pueden aparecer problemas visuales. Ajusta el valor según el nivel y comprueba el resultado con sus sprites y animaciones funcionando juntos.&lt;br /&gt;
&lt;br /&gt;
Las macros normales devuelven el carry desactivado si una carga no cabe en el límite. En ese caso, conserva lo que ya se muestra y vuelve a intentarlo después. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; se saltan la comprobación y también suman sus bytes al total.&lt;br /&gt;
&lt;br /&gt;
== Crear animaciones de gráficos ==&lt;br /&gt;
&lt;br /&gt;
Una animación de tiles se consigue copiando distintas imágenes al mismo lugar de VRAM. Los tiles del nivel siguen apuntando al mismo lugar, pero los gráficos que contienen van cambiando.&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las primeras cuatro imágenes de &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;, con &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes por imagen, y cambia de imagen cada ocho frames. El archivo se registra como recurso general, no como pose de sprite dinámico.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt;, junto a &amp;lt;code&amp;gt;SMMArrow.bin&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ASM del nivel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
!AnimationGraphics = !ResourceSMMArrow&lt;br /&gt;
!Destination = !BG2Line0&lt;br /&gt;
!BytesPerFrame = $0200&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    %ForcedTransferToVRAMFromAddr(#!Destination, !AnimationGraphics, #!BytesPerFrame)&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $9D&lt;br /&gt;
    ORA $13D4|!addr&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    ; Cambiar de imagen cada ocho frames.&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$07&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    ; Obtener 0, $0200, $0400 o $0600 como desplazamiento en el archivo.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$0018&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    ASL&lt;br /&gt;
    CLC&lt;br /&gt;
    ADC.w #!AnimationGraphics&lt;br /&gt;
    STA $00&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    %TransferToVRAM(#!Destination, $00, #(!AnimationGraphics&amp;gt;&amp;gt;16), #!BytesPerFrame)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceSMMArrow&amp;lt;/code&amp;gt; es la dirección que se genera al instalar el recurso y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres se normalizan eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra. En este caso se conserva &amp;lt;code&amp;gt;SMMArrow&amp;lt;/code&amp;gt; tal como está escrito en el nombre del archivo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Destination&amp;lt;/code&amp;gt; elige dónde se muestran los gráficos. Aquí se usa &amp;lt;code&amp;gt;!BG2Line0&amp;lt;/code&amp;gt;; debes colocar en el nivel tiles que utilicen esa zona y asegurarte de que ningún otro recurso la sobrescriba. &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes equivalen a 16 tiles de 8×8 en gráficos de 4 bits por píxel.&lt;br /&gt;
&lt;br /&gt;
El cálculo de este ejemplo está hecho para cuatro imágenes de &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes. Cambiar el tamaño o la cantidad de imágenes requiere ajustar también ese cálculo. Las cuatro imágenes utilizadas deben estar en el mismo banco de origen, porque la transferencia recibe una dirección y un banco por separado.&lt;br /&gt;
&lt;br /&gt;
Si una transferencia normal se rechaza, permanece la imagen anterior y se intenta otra carga en el siguiente cambio de la animación. &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; permite detener la animación junto con el juego. La carga inicial utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; una sola vez; los cambios durante el juego respetan el límite de datos por frame.&lt;br /&gt;
&lt;br /&gt;
== Cambiar paletas durante el juego ==&lt;br /&gt;
&lt;br /&gt;
Para cargar colores sin asignación automática, registra el archivo de paleta como recurso general y cópialo a CGRAM. El destino se expresa como número de color: la paleta 7 comienza en &amp;lt;code&amp;gt;$70&amp;lt;/code&amp;gt; y la 9 en &amp;lt;code&amp;gt;$90&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El archivo &amp;lt;code&amp;gt;SMMArrowPal.bin&amp;lt;/code&amp;gt; del ejemplo contiene 15 colores, es decir, &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes. Se coloca a partir del color 1 de la paleta 7, dejando el color 0 sin modificar.&lt;br /&gt;
&lt;br /&gt;
En &amp;lt;code&amp;gt;DynamicXtreme/SMMArrow.dynamicinfo&amp;lt;/code&amp;gt; puedes declarar ambos recursos:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    SMMArrow.bin&lt;br /&gt;
    SMMArrowPal.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/SMMArrow.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    %TransferResourceToCGRAM(#$71, &amp;quot;SMMArrowPal&amp;quot;)&lt;br /&gt;
    BCC .Return&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SMMArrowPal&amp;lt;/code&amp;gt; corresponde a &amp;lt;code&amp;gt;!ResourceSMMArrowPal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceSMMArrowPalSize&amp;lt;/code&amp;gt;, generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa la misma normalización de los demás recursos: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
Para cambiar los colores durante el juego, realiza la transferencia desde &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; cuando se cumpla la condición que quieras utilizar. Comprueba el carry y, si la copia no se pudo programar, vuelve a intentarlo en otro frame. No hace falta repetir una carga que ya se aceptó si los colores no van a cambiar.&lt;br /&gt;
&lt;br /&gt;
Si eliges una paleta de sprites 8-F para un uso fijo, resérvala primero como se explica al comienzo del artículo. También puedes copiar colores calculados en RAM; para esas variantes consulta [[es/Dynamic_Xtreme_ASM_API#PPU|Transferencias de la API]].&lt;br /&gt;
&lt;br /&gt;
== Cambiar los gráficos del jugador ==&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;PlayerFeatures&amp;lt;/code&amp;gt; habilitado, puedes indicar desde qué archivo se leen los gráficos del jugador. El archivo debe utilizar la misma organización de poses que los gráficos originales de Mario; cambiar la dirección no adapta automáticamente un spritesheet de otro formato.&lt;br /&gt;
&lt;br /&gt;
Registra los gráficos como recurso general. Por ejemplo, con &amp;lt;code&amp;gt;Geno.bin&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;Geno.dynamicinfo&amp;lt;/code&amp;gt; juntos:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Resources:&lt;br /&gt;
    Geno.bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/Geno.dynamicinfo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!ResourceGeno&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!ResourceGeno&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Enable&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGeno&amp;lt;/code&amp;gt; se genera desde el recurso del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores; por ejemplo, &amp;lt;code&amp;gt;my_player&amp;lt;/code&amp;gt; produciría &amp;lt;code&amp;gt;MyPlayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El juego continúa eligiendo las poses del jugador normalmente, pero Dynamic Xtreme lee sus tiles desde el nuevo archivo. Este ejemplo cambia los gráficos, no la paleta ni el comportamiento del personaje.&lt;br /&gt;
&lt;br /&gt;
Para volver a los gráficos habituales, cambia el origen a &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!GFX32Buffer&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_Addr&lt;br /&gt;
    LDA.w #(!GFX32Buffer&amp;gt;&amp;gt;16)&amp;amp;$00FF&lt;br /&gt;
    STA.l DX_Dynamic_Player_GFX_BNK&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
También puedes ejecutar estos cambios al pulsar un botón o al entrar en un estado concreto. No es necesario escribir la misma dirección en cada frame si no cambió el personaje.&lt;br /&gt;
&lt;br /&gt;
=== Cambiar también la paleta del jugador ===&lt;br /&gt;
&lt;br /&gt;
El jugador divide sus colores en partes. En los archivos de 15 colores del ejemplo de Geno, los primeros 4 colores visibles se copian al color &amp;lt;code&amp;gt;$82&amp;lt;/code&amp;gt;, mientras la rutina del jugador toma los últimos 10 desde la dirección que indiques. El color intermedio y la disposición del archivo deben coincidir con el formato esperado por el jugador.&lt;br /&gt;
&lt;br /&gt;
Después de declarar &amp;lt;code&amp;gt;GenoPal.bin&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt;, este fragmento configura su paleta:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; Colores 2-5 de la paleta 8: omitir el primer color del archivo.&lt;br /&gt;
    %ForcedTransferToCGRAMFromAddr(#$82, !ResourceGenoPal+$02, #$0008)&lt;br /&gt;
&lt;br /&gt;
    ; Colores 6-F: la rutina del jugador los toma desde este origen.&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.w #!ResourceGenoPal+$0A&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Addr&lt;br /&gt;
    SEP #$20&lt;br /&gt;
    LDA.b #!ResourceGenoPal&amp;gt;&amp;gt;16&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_BNK&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA.l DX_Dynamic_Player_Palette_Enable&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceGenoPal&amp;lt;/code&amp;gt; se genera al instalar ese recurso del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre sigue la normalización habitual, conservando las mayúsculas ya presentes.&lt;br /&gt;
&lt;br /&gt;
Si el personaje utiliza colores distintos para Mario, Luigi o el estado de fuego, selecciona el recurso correspondiente antes de aplicar este cambio. El código de cambio de jugador del paquete utiliza una tabla de cuatro paletas para esa selección.&lt;br /&gt;
&lt;br /&gt;
== Aplicar un efecto global de paleta ==&lt;br /&gt;
&lt;br /&gt;
Un efecto global permite cambiar los colores de varias paletas con una sola selección. Primero defines el efecto en un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y después indicas desde UberASM qué paletas lo reciben.&lt;br /&gt;
&lt;br /&gt;
=== Preparar el efecto ===&lt;br /&gt;
&lt;br /&gt;
Este ejemplo elimina la saturación de los colores, utilizando &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt;. Guarda lo siguiente como &amp;lt;code&amp;gt;DynamicXtreme/DecreaseSaturation.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;Channel2&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;Ratio2&amp;quot;: 127,&lt;br /&gt;
      &amp;quot;EffectType&amp;quot;: 11&lt;br /&gt;
    }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Channel2 = 0&amp;lt;/code&amp;gt; indica la saturación a la que se quiere llegar y &amp;lt;code&amp;gt;Ratio2 = 127&amp;lt;/code&amp;gt; aplica el cambio completo. Los valores de color siguen estando entre 0 y 31; los ratios utilizan 0-127.&lt;br /&gt;
&lt;br /&gt;
Si adaptas un efecto antiguo cuyos ratios iban de 0 a 31, conserva la proporción del cambio: 0 sigue siendo 0, 31 pasa a 127 y un valor intermedio se convierte aproximadamente con &amp;lt;code&amp;gt;ratio antiguo × 127 ÷ 31&amp;lt;/code&amp;gt;, redondeando al entero más cercano. No multipliques los valores &amp;lt;code&amp;gt;Channel&amp;lt;/code&amp;gt;: siguen usando 0-31. Los archivos antiguos que utilizan &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; también deben indicar el &amp;lt;code&amp;gt;EffectType&amp;lt;/code&amp;gt; actual; por ejemplo, &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt; es 9, &amp;lt;code&amp;gt;MixS&amp;lt;/code&amp;gt; es 11 y &amp;lt;code&amp;gt;MixRG&amp;lt;/code&amp;gt; es 2.&lt;br /&gt;
&lt;br /&gt;
Al instalarlo se genera &amp;lt;code&amp;gt;!PaletteEffectIDDecreaseSaturation0&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El número final es el índice del efecto dentro del archivo, no su ratio. Los nombres se normalizan eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;decrease_saturation&amp;lt;/code&amp;gt; produciría &amp;lt;code&amp;gt;DecreaseSaturation&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Elegir las paletas afectadas ===&lt;br /&gt;
&lt;br /&gt;
Cada bit de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; permite el efecto en una paleta 0-7; &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; hace lo mismo para las paletas 8-F:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor del bit !! Paleta de fondo !! Paleta de sprites&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || 0 || 8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || 1 || 9&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || 2 || A&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || 3 || B&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || 4 || C&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; || 5 || D&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt; || 6 || E&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; || 7 || F&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Puedes combinar bits para elegir varias. Por ejemplo, &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; selecciona las dos primeras y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; selecciona las ocho. En sprites con asignación dinámica, configura también el bit E de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; según quieras que su paleta participe en el efecto global.&lt;br /&gt;
&lt;br /&gt;
=== Aplicar un efecto fijo ===&lt;br /&gt;
&lt;br /&gt;
El siguiente código aplica el efecto a las paletas de fondo 0-7. La máscara de sprites se deja en 0:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/DecreaseSaturation.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$FF&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDDecreaseSaturation0&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
No necesitas repetir la selección en &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; mientras quieras mantener el mismo efecto. Dynamic Xtreme procesa los colores de las paletas habilitadas.&lt;br /&gt;
&lt;br /&gt;
Para quitar el efecto, escribe 0 en el ID global y deja que el sistema procese las paletas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #$0000&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Incluir el color fijo o el color 0,0 ===&lt;br /&gt;
&lt;br /&gt;
Estos dos colores se controlan mediante &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt;. El bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; permite el efecto en el color fijo y &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; en el color 0,0. Para habilitar ambos, utiliza &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, para incluir el color fijo sin cambiar la opción del color 0,0:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    LDA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
    ORA #$01&lt;br /&gt;
    STA.l DX_PPU_ColorEffect_Enable&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hacer que el efecto se repita en un ciclo ===&lt;br /&gt;
&lt;br /&gt;
Para animar un efecto, prepara varios efectos consecutivos dentro del mismo archivo y ve cambiando el ID seleccionado. Este ejemplo utiliza cuatro tonos HSL con el cambio aplicado al máximo. Guarda el archivo como &amp;lt;code&amp;gt;DynamicXtreme/Hue.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0,  &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 8,  &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 16, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 24, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 9 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Al instalarlo, los defines &amp;lt;code&amp;gt;!PaletteEffectIDHue0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDHue3&amp;lt;/code&amp;gt; quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre procede del archivo y utiliza la normalización habitual en PascalCase.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Hue.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
    LDA #$FF&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalBGEnable&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalSPEnable&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDHue0&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $9D&lt;br /&gt;
    ORA $13D4|!addr&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$07&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!PaletteEffectIDHue3&lt;br /&gt;
    BCS .Restart&lt;br /&gt;
    INC A&lt;br /&gt;
    BRA .Store&lt;br /&gt;
.Restart&lt;br /&gt;
    LDA #!PaletteEffectIDHue0&lt;br /&gt;
.Store&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El código mantiene cada efecto durante ocho frames y vuelve al primero después de mostrar el último. Puedes añadir más pasos al archivo y cambiar el define del último efecto para obtener una animación más suave.&lt;br /&gt;
&lt;br /&gt;
=== Hacer una transición que se detiene al terminar ===&lt;br /&gt;
&lt;br /&gt;
Para cambiar poco a poco los colores y conservar el resultado final, utiliza una secuencia como esta. El ejemplo reduce el rojo y el verde para dar un aspecto azulado al nivel. Guarda el archivo como &amp;lt;code&amp;gt;DynamicXtreme/Night.paleffect&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Effects&amp;quot;: [&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 0,   &amp;quot;Ratio2&amp;quot;: 0,   &amp;quot;EffectType&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 42,  &amp;quot;Ratio2&amp;quot;: 42,  &amp;quot;EffectType&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 85,  &amp;quot;Ratio2&amp;quot;: 85,  &amp;quot;EffectType&amp;quot;: 2 },&lt;br /&gt;
    { &amp;quot;Channel1&amp;quot;: 0, &amp;quot;Channel2&amp;quot;: 0, &amp;quot;Ratio1&amp;quot;: 127, &amp;quot;Ratio2&amp;quot;: 127, &amp;quot;EffectType&amp;quot;: 2 }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Selecciona &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt;, con las máscaras de paleta del ejemplo anterior. Para avanzar y detenerte al llegar al último, utiliza este &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incpale &amp;quot;DynamicXtreme/Night.paleffect&amp;quot;&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    LDA $9D&lt;br /&gt;
    ORA $13D4|!addr&lt;br /&gt;
    BNE .Return&lt;br /&gt;
    LDA.l DX_SyncTimer&lt;br /&gt;
    AND #$07&lt;br /&gt;
    BNE .Return&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
    CMP #!PaletteEffectIDNight3&lt;br /&gt;
    BCS .Done&lt;br /&gt;
    INC A&lt;br /&gt;
    STA.l DX_Dynamic_Palettes_GlobalEffectID&lt;br /&gt;
.Done&lt;br /&gt;
    SEP #$20&lt;br /&gt;
.Return&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PaletteEffectIDNight0&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!PaletteEffectIDNight3&amp;lt;/code&amp;gt; se generan desde &amp;lt;code&amp;gt;Night.paleffect&amp;lt;/code&amp;gt; y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres siguen la normalización en PascalCase. Este código avanza por los efectos de mezcla del archivo; para una transición hacia otra paleta completa, utiliza un efecto &amp;lt;code&amp;gt;PalTransitionRGB&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;PalTransitionHSL&amp;lt;/code&amp;gt;, explicado en [[es/Dynamic_Xtreme_files_and_formats#Transiciones_de_paleta|Archivos y formatos]].&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21354</id>
		<title>es/Dynamic Xtreme</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21354"/>
		<updated>2026-10-24T05:01:14Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es una herramienta de soporte dinámico avanzada para Super Mario World en el SNES. Desarrollada para la comunidad de ROM hacking, permite realizar cambios gráficos y de paletas en tiempo real durante la ejecución del juego, ampliando considerablemente las capacidades técnicas originales del hardware del SNES.La herramienta se centra en ofrecer un sistema completo y flexible de gráficos dinámicos, con énfasis en el rendimiento y la modularidad. &lt;br /&gt;
&lt;br /&gt;
Entre sus características principales se incluyen:&lt;br /&gt;
* Cambios gráficos y de paleta en tiempo real (on-the-fly).&lt;br /&gt;
* El sistema de Dynamic Sprite más potente y flexible disponible para Super Mario World.&lt;br /&gt;
* Advanced Drawing System, que permite dibujar cualquier frame registrado en pantalla con control total sobre prioridad, capa, desplazamiento (offset) y propiedades.&lt;br /&gt;
* Efectos de paleta avanzados, que incluyen modificación en tiempo real mediante tono (hue), saturación, brillo, fusión de colores, transiciones suaves y control individual de canales RGB y HSL.&lt;br /&gt;
* Reemplazo completo de gráficos y paletas del jugador, compatible con cualquier tamaño de Mario, cualquier cantidad de frames y cualquier estilo de animación.&lt;br /&gt;
* Soporte total para el reemplazo de gráficos de Yoshi.&lt;br /&gt;
* Optimizaciones intensivas en el NMI-handler para maximizar el rendimiento.&lt;br /&gt;
&lt;br /&gt;
Todas las funciones de Dynamic Xtreme son completamente opcionales y modulares, lo que permite instalar o desinstalar cualquiera de ellas en cualquier momento sin generar código innecesario ni conflictos con otras herramientas.La herramienta fue creada con el objetivo de facilitar la implementación de efectos visuales complejos en hacks de Super Mario World manteniendo un alto nivel de compatibilidad y estabilidad.&lt;br /&gt;
&lt;br /&gt;
== Objetivos del proyecto ==&lt;br /&gt;
&lt;br /&gt;
El principal objetivo de Dynamic Xtreme es facilitar el uso de sprites dinámicos y ofrecer un soporte completo para cambios de gráficos, paletas y tilemaps en tiempo real.&lt;br /&gt;
&lt;br /&gt;
El proyecto busca aprovechar al máximo el potencial del SNES sin requerir que el usuario tenga conocimientos avanzados sobre el hardware interno de la consola. Muchos sistemas dinámicos tradicionales suelen ser complejos y dependen fuertemente de conceptos técnicos como VRAM, CGRAM, OAM o DMA. Dynamic Xtreme intenta abstraer gran parte de esa complejidad mediante herramientas y formatos más modernos, legibles y fáciles de utilizar.&lt;br /&gt;
&lt;br /&gt;
Otro de los objetivos principales del proyecto es mantener un alto rendimiento incluso en situaciones visualmente complejas, permitiendo el uso intensivo de gráficos dinámicos, efectos de paletas y sistemas avanzados de renderizado sin comprometer innecesariamente la performance.&lt;br /&gt;
&lt;br /&gt;
Además, Dynamic Xtreme busca que los sprites dinámicos puedan utilizarse de una forma tan natural y sencilla como si fueran sprites normales. La idea es que las personas enfocadas en level design o creación de contenido no necesiten preocuparse constantemente por las limitaciones técnicas internas del sistema y puedan trabajar con recursos dinámicos de forma transparente y práctica.&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guía rápida de instalación:&#039;&#039;&#039; [[es/Dynamic_Xtreme_Quick_Start|Quick Start]]&lt;br /&gt;
&lt;br /&gt;
== Herramientas y Soporte ==&lt;br /&gt;
&lt;br /&gt;
== Archivos y formatos ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Artículo relacionado:&#039;&#039;&#039; [[es/Dynamic_Xtreme_files_and_formats|Archivos y Formatos de Dynamic Xtreme]]&lt;br /&gt;
&lt;br /&gt;
== Guía de creación de sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Para aprender a preparar, programar, cargar y dibujar un sprite dinámico, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites dinámicos con Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
== Dynamic Xtreme con UberASM ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_UberASM_guide|guía de Dynamic Xtreme con UberASM]] muestra cómo reservar paletas, configurar el espacio para sprites dinámicos y el límite de datos por frame, crear animaciones, cambiar gráficos del jugador y aplicar efectos de paleta.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]] explica cómo utilizar las variables, los defines, las rutinas y las macros de Dynamic Xtreme. Incluye los datos que necesita cada llamada, sus resultados y ejemplos de uso para trabajar con poses, dibujo, paletas, efectos de color y transferencias de gráficos, además de las macros de multiplicación y división.&lt;br /&gt;
&lt;br /&gt;
== Funcionamiento interno del sistema ==&lt;br /&gt;
&lt;br /&gt;
== Compatibilidad ==&lt;br /&gt;
&lt;br /&gt;
== Recursos hechos con Dynamic Xtreme ==&lt;br /&gt;
&lt;br /&gt;
La mayoría de los recursos desarrollados para Dynamic Xtreme no suelen publicarse en sitios tradicionales como SMW Central debido a que muchos de ellos dependen directamente del framework y sus sistemas avanzados.&lt;br /&gt;
&lt;br /&gt;
En su lugar, los recursos, ejemplos, sistemas y proyectos relacionados con Dynamic Xtreme se encuentran recopilados principalmente en:&lt;br /&gt;
&lt;br /&gt;
https://snestorage.dev&lt;br /&gt;
&lt;br /&gt;
Allí es posible encontrar sprites, sistemas de jugador, efectos gráficos, ejemplos técnicos y otros recursos diseñados específicamente para trabajar con Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
== Conclusión ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es un proyecto orientado a modernizar y simplificar el uso de sistemas dinámicos en Super Mario World, ofreciendo herramientas más flexibles, potentes y fáciles de utilizar sin perder compatibilidad ni control avanzado.&lt;br /&gt;
&lt;br /&gt;
El proyecto continúa evolucionando constantemente con nuevas optimizaciones, formatos y herramientas orientadas tanto a usuarios avanzados como a personas que recién comienzan a trabajar con gráficos dinámicos en SNES.&lt;br /&gt;
&lt;br /&gt;
La intención principal de Dynamic Xtreme es permitir la creación de recursos y sistemas cada vez más complejos, manteniendo al mismo tiempo un workflow más limpio, mantenible y accesible para la comunidad.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21353</id>
		<title>es/Dynamic Xtreme</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme&amp;diff=21353"/>
		<updated>2026-10-24T04:54:57Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: /* API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme}}&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es una herramienta de soporte dinámico avanzada para Super Mario World en el SNES. Desarrollada para la comunidad de ROM hacking, permite realizar cambios gráficos y de paletas en tiempo real durante la ejecución del juego, ampliando considerablemente las capacidades técnicas originales del hardware del SNES.La herramienta se centra en ofrecer un sistema completo y flexible de gráficos dinámicos, con énfasis en el rendimiento y la modularidad. &lt;br /&gt;
&lt;br /&gt;
Entre sus características principales se incluyen:&lt;br /&gt;
* Cambios gráficos y de paleta en tiempo real (on-the-fly).&lt;br /&gt;
* El sistema de Dynamic Sprite más potente y flexible disponible para Super Mario World.&lt;br /&gt;
* Advanced Drawing System, que permite dibujar cualquier frame registrado en pantalla con control total sobre prioridad, capa, desplazamiento (offset) y propiedades.&lt;br /&gt;
* Efectos de paleta avanzados, que incluyen modificación en tiempo real mediante tono (hue), saturación, brillo, fusión de colores, transiciones suaves y control individual de canales RGB y HSL.&lt;br /&gt;
* Reemplazo completo de gráficos y paletas del jugador, compatible con cualquier tamaño de Mario, cualquier cantidad de frames y cualquier estilo de animación.&lt;br /&gt;
* Soporte total para el reemplazo de gráficos de Yoshi.&lt;br /&gt;
* Optimizaciones intensivas en el NMI-handler para maximizar el rendimiento.&lt;br /&gt;
&lt;br /&gt;
Todas las funciones de Dynamic Xtreme son completamente opcionales y modulares, lo que permite instalar o desinstalar cualquiera de ellas en cualquier momento sin generar código innecesario ni conflictos con otras herramientas.La herramienta fue creada con el objetivo de facilitar la implementación de efectos visuales complejos en hacks de Super Mario World manteniendo un alto nivel de compatibilidad y estabilidad.&lt;br /&gt;
&lt;br /&gt;
== Objetivos del proyecto ==&lt;br /&gt;
&lt;br /&gt;
El principal objetivo de Dynamic Xtreme es facilitar el uso de sprites dinámicos y ofrecer un soporte completo para cambios de gráficos, paletas y tilemaps en tiempo real.&lt;br /&gt;
&lt;br /&gt;
El proyecto busca aprovechar al máximo el potencial del SNES sin requerir que el usuario tenga conocimientos avanzados sobre el hardware interno de la consola. Muchos sistemas dinámicos tradicionales suelen ser complejos y dependen fuertemente de conceptos técnicos como VRAM, CGRAM, OAM o DMA. Dynamic Xtreme intenta abstraer gran parte de esa complejidad mediante herramientas y formatos más modernos, legibles y fáciles de utilizar.&lt;br /&gt;
&lt;br /&gt;
Otro de los objetivos principales del proyecto es mantener un alto rendimiento incluso en situaciones visualmente complejas, permitiendo el uso intensivo de gráficos dinámicos, efectos de paletas y sistemas avanzados de renderizado sin comprometer innecesariamente la performance.&lt;br /&gt;
&lt;br /&gt;
Además, Dynamic Xtreme busca que los sprites dinámicos puedan utilizarse de una forma tan natural y sencilla como si fueran sprites normales. La idea es que las personas enfocadas en level design o creación de contenido no necesiten preocuparse constantemente por las limitaciones técnicas internas del sistema y puedan trabajar con recursos dinámicos de forma transparente y práctica.&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guía rápida de instalación:&#039;&#039;&#039; [[es/Dynamic_Xtreme_Quick_Start|Quick Start]]&lt;br /&gt;
&lt;br /&gt;
== Herramientas y Soporte ==&lt;br /&gt;
&lt;br /&gt;
== Archivos y formatos ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Artículo relacionado:&#039;&#039;&#039; [[es/Dynamic_Xtreme_files_and_formats|Archivos y Formatos de Dynamic Xtreme]]&lt;br /&gt;
&lt;br /&gt;
== Guía de creación de sprites dinámicos ==&lt;br /&gt;
&lt;br /&gt;
Para aprender a preparar, programar, cargar y dibujar un sprite dinámico, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites dinámicos con Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
&lt;br /&gt;
La [[es/Dynamic_Xtreme_ASM_API|referencia de la API ASM]] explica cómo utilizar las variables, los defines, las rutinas y las macros de Dynamic Xtreme. Incluye los datos que necesita cada llamada, sus resultados y ejemplos de uso para trabajar con poses, dibujo, paletas, efectos de color y transferencias de gráficos, además de las macros de multiplicación y división.&lt;br /&gt;
&lt;br /&gt;
== Funcionamiento interno del sistema ==&lt;br /&gt;
&lt;br /&gt;
== Compatibilidad ==&lt;br /&gt;
&lt;br /&gt;
== Recursos hechos con Dynamic Xtreme ==&lt;br /&gt;
&lt;br /&gt;
La mayoría de los recursos desarrollados para Dynamic Xtreme no suelen publicarse en sitios tradicionales como SMW Central debido a que muchos de ellos dependen directamente del framework y sus sistemas avanzados.&lt;br /&gt;
&lt;br /&gt;
En su lugar, los recursos, ejemplos, sistemas y proyectos relacionados con Dynamic Xtreme se encuentran recopilados principalmente en:&lt;br /&gt;
&lt;br /&gt;
https://snestorage.com&lt;br /&gt;
&lt;br /&gt;
Allí es posible encontrar sprites, sistemas de jugador, efectos gráficos, ejemplos técnicos y otros recursos diseñados específicamente para trabajar con Dynamic Xtreme.&lt;br /&gt;
&lt;br /&gt;
== Conclusión ==&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme es un proyecto orientado a modernizar y simplificar el uso de sistemas dinámicos en Super Mario World, ofreciendo herramientas más flexibles, potentes y fáciles de utilizar sin perder compatibilidad ni control avanzado.&lt;br /&gt;
&lt;br /&gt;
El proyecto continúa evolucionando constantemente con nuevas optimizaciones, formatos y herramientas orientadas tanto a usuarios avanzados como a personas que recién comienzan a trabajar con gráficos dinámicos en SNES.&lt;br /&gt;
&lt;br /&gt;
La intención principal de Dynamic Xtreme es permitir la creación de recursos y sistemas cada vez más complejos, manteniendo al mismo tiempo un workflow más limpio, mantenible y accesible para la comunidad.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_ASM_API&amp;diff=21352</id>
		<title>es/Dynamic Xtreme ASM API</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_ASM_API&amp;diff=21352"/>
		<updated>2026-10-24T04:46:06Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_ASM_API}}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Para aprender a organizar un sprite completo, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites]].&lt;br /&gt;
&lt;br /&gt;
== Variables y defines ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Los nombres de variables generales comienzan con &amp;lt;code&amp;gt;DX_&amp;lt;/code&amp;gt; y se escriben sin &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt;, por ejemplo &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt;. Los defines como &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; sí llevan &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt;. Conserva la escritura exacta del nombre que aparece en el archivo.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Variables generales ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Contadores y cantidad de datos por frame ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_SyncTimer&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_CurrentDataSend&amp;lt;/code&amp;gt; || 2 bytes || Cantidad de bytes que ya se programaron para transferir durante el frame actual. La actualizan las rutinas de carga.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_MaxDataPerFrame&amp;lt;/code&amp;gt; || 2 bytes || Límite de bytes que las cargas normales pueden programar en un frame. Las variantes &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; pueden superarlo.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Poses cargadas en VRAM ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Length&amp;lt;/code&amp;gt; || 1 byte || Cantidad de poses registradas actualmente en la caché.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_HashSize&amp;lt;/code&amp;gt; || 128 valores de 1 byte || Ayuda a encontrar las poses por su ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_ID&amp;lt;/code&amp;gt; || 128 valores de 2 bytes || ID de cada pose registrada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_Offset&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Pose_TimeLastUse&amp;lt;/code&amp;gt; || 128 valores de 2 bytes || Valor de &amp;lt;code&amp;gt;DX_Timer&amp;lt;/code&amp;gt; de la última vez que se utilizó cada pose. Evita reemplazar gráficos que todavía se están mostrando.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Size&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_Dynamic_Tile_Pose&amp;lt;/code&amp;gt; || 128 bytes compartidos || Describen las partes libres u ocupadas de VRAM. Son dos nombres para el mismo espacio de memoria.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Tile_Offset&amp;lt;/code&amp;gt; || 128 valores de 1 byte || Ayuda al sistema a recorrer las partes libres y ocupadas de VRAM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Paletas y efecto global ====&lt;br /&gt;
&lt;br /&gt;
Las tablas de 16 paletas utilizan el orden 0-F. En las tablas de valores de 2 bytes, la paleta 1 comienza en &amp;lt;code&amp;gt;+2&amp;lt;/code&amp;gt;, la 2 en &amp;lt;code&amp;gt;+4&amp;lt;/code&amp;gt;, y así sucesivamente.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalBGEnable&amp;lt;/code&amp;gt; || 1 byte || Cada bit indica si una de las paletas 0-7 recibe el efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalSPEnable&amp;lt;/code&amp;gt; || 1 byte || Cada bit indica si una de las paletas de sprites 8-F recibe el efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_GlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || ID del efecto global que se quiere aplicar. El valor 0 indica que no se aplica un efecto global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Último efecto global revisado por el sistema. Se utiliza para detectar cambios.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_LastGlobalEffectIDPerPal&amp;lt;/code&amp;gt; || 16 valores de 2 bytes || Último efecto global calculado para cada paleta. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; significa que aún no hay un resultado; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt;, que hay una actualización pendiente y se conserva el resultado anterior.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; || 16 valores de 2 bytes || ID asociado a cada paleta. &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; indica que está libre; &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; la excluye de la selección automática.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_Updated&amp;lt;/code&amp;gt; || 16 valores de 1 byte || Indica cuáles paletas ya se actualizaron durante el frame. Uso interno.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_DisableTimer&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Palettes_EffectEnabled&amp;lt;/code&amp;gt; || 1 byte || Registra qué paletas de sprites se utilizan con efectos. Uso interno del manejo de paletas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para reservar una paleta de sprites y evitar que la selección automática la utilice, su entrada de &amp;lt;code&amp;gt;DX_Dynamic_Palettes_ID&amp;lt;/code&amp;gt; debe contener &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt;. Haz la reserva antes de que los sprites comiencen a solicitar paletas.&lt;br /&gt;
&lt;br /&gt;
==== Copias de colores y resultados de efectos ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; || 512 bytes || Copia de trabajo de las 256 entradas de color, con 2 bytes por color. Es la fuente de las variantes &amp;lt;code&amp;gt;SetRGBBaseDefault&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SetHSLBaseDefault&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; || 768 bytes || Colores originales separados en rojo, verde y azul: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt; || 768 bytes || Colores originales separados en tono, saturación y luminosidad: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LocalEffectBuffer&amp;lt;/code&amp;gt; || 768 bytes || Espacio de trabajo para el resultado de un efecto local antes de combinarlo con el global.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LocalEffectID&amp;lt;/code&amp;gt; || 16 valores de 2 bytes || ID del efecto local aplicado a cada paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt; || 512 bytes || Colores resultantes en formato de SNES, con 2 bytes por color. Las variantes &amp;lt;code&amp;gt;AndMergeDefault&amp;lt;/code&amp;gt; escriben aquí.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseRGBPaletteLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Cada bit indica si ya se preparó la base RGB de una paleta de fondo o de sprites.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPBaseHSLPaletteLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Lo mismo para las bases HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_BGEffectLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_CGRAM_SPEffectLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Cada bit indica si ya hay un resultado del efecto para esa paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_LastPlayerPal&amp;lt;/code&amp;gt; || 2 bytes || Dirección de la última paleta del jugador procesada. El sistema la compara para detectar cambios.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Color fijo y primer color de la paleta ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_Enable&amp;lt;/code&amp;gt; || 1 byte || Activa la participación en el efecto global: bit &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; para el color fijo y bit &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; para el color 0,0. &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; permite ambos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_BaseLoaded&amp;lt;/code&amp;gt; || 1 byte || Indica si se guardaron sus colores originales. Utiliza un bit por destino: &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_ColorEffect_RGBBaseLoaded&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_ColorEffect_HSLBaseLoaded&amp;lt;/code&amp;gt; || 1 byte cada una || Indican si sus colores ya se prepararon en RGB o HSL, con los mismos bits.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Mirror&amp;lt;/code&amp;gt; || 2 bytes || Copia del color fijo que utiliza la actualización habitual del juego.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Base&amp;lt;/code&amp;gt; || 2 bytes || Color fijo original, antes de los efectos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_RGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_FixedColor_HSLBase&amp;lt;/code&amp;gt; || 3 bytes cada una || Color fijo original separado en RGB o HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_Result&amp;lt;/code&amp;gt; || 2 bytes || Color fijo calculado después del efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_FixedColor_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Último efecto global calculado para el color fijo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Base&amp;lt;/code&amp;gt; || 2 bytes || Color 0,0 original.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_RGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_HSLBase&amp;lt;/code&amp;gt; || 3 bytes cada una || Color 0,0 original separado en RGB o HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Result&amp;lt;/code&amp;gt; || 2 bytes || Color 0,0 que se quiere mostrar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_LastGlobalEffectID&amp;lt;/code&amp;gt; || 2 bytes || Último efecto global calculado para el color 0,0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_PaletteColor00_Update&amp;lt;/code&amp;gt; || 1 byte || Un valor distinto de 0 solicita copiar &amp;lt;code&amp;gt;Result&amp;lt;/code&amp;gt; al color 0,0 durante NMI. Después de copiarlo, el sistema vuelve a poner esta variable en 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Transferencias pendientes ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Contenido&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Length&amp;lt;/code&amp;gt; || Cantidad de copias de gráficos pendientes, en 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || Cantidad de bytes de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Offset&amp;lt;/code&amp;gt; || Destino de cada copia en VRAM, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_Source&amp;lt;/code&amp;gt; || Dirección de origen de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_VRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || Banco de origen de cada copia. La tabla reserva 2 bytes por entrada.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Length&amp;lt;/code&amp;gt; || Cantidad de copias de colores pendientes, en 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceLength&amp;lt;/code&amp;gt; || Cantidad de bytes de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Offset&amp;lt;/code&amp;gt; || Primer color de destino de cada copia, en valores de 1 byte.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_Source&amp;lt;/code&amp;gt; || Dirección de origen de cada copia, en valores de 2 bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_PPU_CGRAM_Transfer_SourceBNK&amp;lt;/code&amp;gt; || Banco de origen de cada copia.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Jugador y Yoshi ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Tamaño !! Para qué sirve&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_Enable&amp;lt;/code&amp;gt; || 1 byte || 0 desactiva la carga de gráficos mediante este sistema; un valor distinto de 0 la activa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_Addr&amp;lt;/code&amp;gt; || 2 bytes || Dirección de inicio de los gráficos del jugador dentro del banco indicado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_GFX_BNK&amp;lt;/code&amp;gt; || 2 bytes reservados || Banco de origen de los gráficos del jugador. El banco se indica en el byte bajo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_Enable&amp;lt;/code&amp;gt; || 1 byte || 0 desactiva el manejo de paleta del jugador mediante este sistema; un valor distinto de 0 lo activa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_Addr&amp;lt;/code&amp;gt; || 2 bytes || Dirección de origen de la paleta del jugador.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_Palette_BNK&amp;lt;/code&amp;gt; || 1 byte || Banco de la paleta. Cuando es 0, la rutina toma la dirección de paleta que utiliza el juego.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Player_CustomPlayer&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DX_Dynamic_Player_LastCustomPlayer&amp;lt;/code&amp;gt; || 1 byte cada una || Variables reservadas para identificar al jugador personalizado y el anterior. La inicialización las pone en 0 y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;; actualmente no seleccionan por sí solas los gráficos de un personaje.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_VRAMEnable&amp;lt;/code&amp;gt; || 1 byte || 0 desactiva la carga de gráficos de Yoshi mediante este sistema; un valor distinto de 0 la activa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_Addr&amp;lt;/code&amp;gt; || 2 bytes || Dirección de inicio de los gráficos de Yoshi dentro de su banco.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DX_Dynamic_Yoshi_BNK&amp;lt;/code&amp;gt; || 1 byte || Banco de origen de los gráficos de Yoshi.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Dibujo y variables de sprites ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_Drawing_InitialIndexHighPriority&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_Drawing_InitialIndexLowPriority&amp;lt;/code&amp;gt; ocupan 1 byte cada una y llevan la cuenta de las posiciones disponibles para dibujar sprites de prioridad alta o baja. &amp;lt;code&amp;gt;DX_Drawing_OAMMap&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Las variables individuales de sprites se definen en &amp;lt;code&amp;gt;DynamicXSpritesTables.asm&amp;lt;/code&amp;gt;. Los archivos &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; permiten utilizar los mismos nombres para los tres tipos:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Nombre para el sprite !! Qué guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt; || Pose que se quiere mostrar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt; || Última pose que se consiguió y puede dibujarse. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; || Entrada donde el sistema tiene registrada la ubicación de sus gráficos. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt; || Volteo general, volteo adicional de la pose y volteo que se utiliza para dibujar.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; || Paleta asignada: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; para la 8, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; para la 9, y así hasta &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; para la F. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; cuando se utiliza asignación dinámica.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; || Opciones &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: efecto global y elección de paleta o grupo de paletas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; || Modo de asignación: automático, manual o manual sin cargar colores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt; || Variante del sprite y última variante procesada al manejar su paleta. &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt; se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen,x&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SafeFrameLowByte,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!SafeFrameHighByte,x&amp;lt;/code&amp;gt; || Último frame en que se intentó solicitar una pose, para evitar repetir el trabajo durante el mismo frame.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AnimationIndex,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AnimationPoseIndex,x&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AnimationTimer,x&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!State,x&amp;lt;/code&amp;gt; || Variable para el estado o comportamiento del recurso.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada variable de esta tabla ocupa 1 byte por sprite. Hay &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; entradas para normales, 20 para cluster y 10 para extended. No utilices &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; como cantidad de entradas de cluster o extended.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DX_FreeRams&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DX_FreeRams2&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Defines fijos ===&lt;br /&gt;
&lt;br /&gt;
Estos nombres representan configuraciones y direcciones conocidas. No son variables que cambian durante el juego.&lt;br /&gt;
&lt;br /&gt;
==== Compatibilidad con LoROM y SA-1 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; detecta el tipo de ROM y elige los valores correspondientes. Utiliza estos nombres para que tu código funcione en ambos casos.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! LoROM !! SA-1 !! Uso&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!sa1&amp;lt;/code&amp;gt; || 0 || 1 || Permite elegir código distinto según el tipo de ROM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!dp&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$3000&amp;lt;/code&amp;gt; || Ajuste de las direcciones de página directa.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!addr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; || Ajuste de las direcciones RAM que lo requieren, por ejemplo &amp;lt;code&amp;gt;$0100|!addr&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!rom&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$800000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$000000&amp;lt;/code&amp;gt; || Ajuste utilizado al acceder a direcciones del código original del juego.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MaxSprites&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; (12) || &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; (22) || Cantidad de posiciones de sprites normales.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MultiplicationResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4216&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2306&amp;lt;/code&amp;gt; || Dirección donde se lee el resultado de una multiplicación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DivisionResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4214&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2306&amp;lt;/code&amp;gt; || Dirección donde se lee el cociente de una división.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RemainderResult&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4216&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2308&amp;lt;/code&amp;gt; || Dirección donde se lee el resto de una división.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Otros defines utilizados para colocar las variables son &amp;lt;code&amp;gt;!normalBnk&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalCopyBNK&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!Variables&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Variables2&amp;lt;/code&amp;gt;. Normalmente basta con utilizar el nombre de cada variable &amp;lt;code&amp;gt;DX_...&amp;lt;/code&amp;gt;, sin calcular su dirección a partir de estos valores.&lt;br /&gt;
&lt;br /&gt;
==== Direcciones de gráficos en VRAM ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia !! Línea 0 !! Avance por línea !! Ejemplo&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG1LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG1Line1 = $0100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG2LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG2Line1 = $0900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG1LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG1Line1 = $1100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!FG3LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$1800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!FG3Line1 = $1900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG2LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG2Line1 = $2100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BG3LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$2800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!BG3Line1 = $2900&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LG1LineN&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!LG4LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$4000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4400&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4800&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$4C00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!LG1Line1 = $4080&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SP1LineN&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;!SP4LineN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6800&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$7000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$7800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!SP4Line1 = $7900&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Layer1Tilemap = $3000&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Layer2Tilemap = $3800&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
==== Configuraciones de espacio para poses dinámicas ====&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt; se entregan a &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt;. El nombre indica qué áreas de gráficos se permiten utilizar. &amp;lt;code&amp;gt;FirstHalf&amp;lt;/code&amp;gt; significa primera mitad y &amp;lt;code&amp;gt;SecondHalf&amp;lt;/code&amp;gt;, segunda mitad. Los nombres con &amp;lt;code&amp;gt;WithPlayer&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;WithDSX&amp;lt;/code&amp;gt; corresponden a las configuraciones previstas para esos casos.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Valor !! Define&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$07&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$09&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigFirstHalfSP1WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP11WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0D&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3ndSP4&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$0F&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2andSP34&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$11&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$13&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithPlayer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$15&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP3ndSP4WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$16&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$17&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP2andSP34WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$18&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$19&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1A&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSecondHalfSP1andSP234WithPlayerAndDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;!DynamicSpaceConfigSP1234WithPlayerAndDSX&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres de esta tabla se escriben exactamente como aparecen en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, incluidos nombres como &amp;lt;code&amp;gt;SecondHalfSSP4&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;SP11WithPlayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Otras constantes ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! Valor o uso&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AN2Buffer1&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!AN2Buffer2&amp;lt;/code&amp;gt; || Direcciones &amp;lt;code&amp;gt;$7EC100&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$7EAD00&amp;lt;/code&amp;gt; utilizadas para datos de animación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!GFX32Buffer&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$7E2000&amp;lt;/code&amp;gt;, dirección del buffer habitual de GFX32.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PlayerPaletteColor2To5&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$00B280&amp;lt;/code&amp;gt;, datos de los colores 2-5 de la paleta del jugador.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PlayerBasePalette&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$00B2C8&amp;lt;/code&amp;gt;, datos de la paleta base del jugador.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!VRAMTransferSize&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!CGRAMTransferSize&amp;lt;/code&amp;gt; || 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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las opciones de instalación, como &amp;lt;code&amp;gt;!DynamicPoses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DrawingSystem&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!GraphicsChange&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalettesChange&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalettesEffects&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PlayerFeatures&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!YoshiFeatures&amp;lt;/code&amp;gt;, se incluyen desde &amp;lt;code&amp;gt;Options.asm&amp;lt;/code&amp;gt;. Sus valores indican qué funciones se instalaron; no se cambian durante el juego.&lt;br /&gt;
&lt;br /&gt;
=== Defines generados ===&lt;br /&gt;
&lt;br /&gt;
Dynamic Xtreme crea estos defines al instalar los recursos y los añade a &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
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, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;my-sprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;my sprite&amp;lt;/code&amp;gt; se convierten en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. 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 &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Poses dinámicas y poses de dibujo ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia o ejemplo !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; || ID de unos gráficos de pose declarados en el DynamicInfo. Se utiliza para solicitar su carga con &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseMySprite000&amp;lt;/code&amp;gt; || Dirección ROM de esos gráficos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseMySprite000Size&amp;lt;/code&amp;gt; || Tamaño de esos gráficos en bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; || ID de una pose del DrawInfo. Se utiliza para dibujarla con &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;DrawStatic&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; || Distancia horizontal calculada desde el DrawInfo para saber cuándo el sprite deja de verse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; || Distancia vertical calculada desde el DrawInfo para la misma comprobación.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; no se utiliza en lugar de un &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Paletas y efectos ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia o ejemplo !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteIDMyPalette&amp;lt;/code&amp;gt; || ID de una paleta declarada desde el DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyPalette&amp;lt;/code&amp;gt; || Dirección ROM de sus colores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyPaletteSize&amp;lt;/code&amp;gt; || Tamaño de la paleta en bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; || Indica dónde comienza la lista de paletas de ese DynamicInfo. Se entrega a &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; y a sus variantes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; || ID de un efecto de &amp;lt;code&amp;gt;my_effect.paleffect&amp;lt;/code&amp;gt;. El número final identifica el efecto dentro del archivo; los IDs globales comienzan en 1.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyTargetRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PaletteMyTargetHSL&amp;lt;/code&amp;gt; || Dirección ROM de una paleta de destino convertida para una transición RGB o HSL. Se genera cuando un efecto necesita esa paleta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteMyTargetRGBSize&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PaletteMyTargetHSLSize&amp;lt;/code&amp;gt; || Tamaño en bytes de esas paletas convertidas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres de los ejemplos usan la misma normalización: &amp;lt;code&amp;gt;my_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyPalette&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. Los defines se generan durante la instalación y quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Recursos generales y buffers ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Familia o ejemplo !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceIDMyResource&amp;lt;/code&amp;gt; || ID de un recurso general del DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceMyResource&amp;lt;/code&amp;gt; || Dirección ROM de ese recurso.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!ResourceMyResourceSize&amp;lt;/code&amp;gt; || Tamaño del recurso en bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferIDMyBuffer&amp;lt;/code&amp;gt; || ID de un buffer insertado por la herramienta.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferMyBuffer&amp;lt;/code&amp;gt; || Dirección del buffer insertado en la ROM; no es una variable temporal de RAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferMyBufferSize&amp;lt;/code&amp;gt; || Tamaño del buffer en bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Los nombres dependen de los recursos instalados. Se normalizan del mismo modo: &amp;lt;code&amp;gt;my_resource&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyResource&amp;lt;/code&amp;gt;. Consulta &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; para ver los nombres y valores de tu instalación.&lt;br /&gt;
&lt;br /&gt;
==== Cantidades y tablas generadas ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define !! Qué representa&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfDynamicPoses&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfPoses&amp;lt;/code&amp;gt; || Cantidad de poses dinámicas y de poses de dibujo instaladas, respectivamente.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfPalettes&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfResources&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!NumberOfBuffers&amp;lt;/code&amp;gt; || Cantidad de paletas normales, recursos generales y buffers insertados.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!NumberOfPaletteEffects&amp;lt;/code&amp;gt; || 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 &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteTableSize&amp;lt;/code&amp;gt; || Cantidad total de entradas en las listas de paletas de los DynamicInfo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteIDTables&amp;lt;/code&amp;gt; || Dirección de la tabla de IDs de esas listas de paletas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteAddrTables&amp;lt;/code&amp;gt; || Dirección de la tabla con las direcciones ROM de sus colores.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsTypes&amp;lt;/code&amp;gt; || Tabla con el tipo de cada efecto instalado.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsChannels1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsChannels2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsChannels3&amp;lt;/code&amp;gt; || Tablas con los valores de color de cada efecto.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PaletteEffectsRatios1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsRatios2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsRatios3&amp;lt;/code&amp;gt; || Tablas con los ratios que controlan cuánto se aplica cada cambio.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!BufferTable&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteTables&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteEffectsTable&amp;lt;/code&amp;gt; || Direcciones de las tablas que el parche publica para esos datos.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Defines de rutinas ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Define o familia !! Uso&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AllowedGameMode&amp;lt;/code&amp;gt; || Comprueba si el modo de juego actual permite procesar las operaciones correspondientes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; || Elige las partes de VRAM disponibles para poses dinámicas.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; || Solicita una pose por su ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; || Prepara las copias de gráficos de una pose a VRAM.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SetPropertyAndOffset&amp;lt;/code&amp;gt; || Obtiene la ubicación y propiedades de los gráficos de una pose dinámica para dibujarla.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Draw&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!Draw_Return&amp;lt;/code&amp;gt; || Entrada y punto de retorno utilizados por las rutinas de dibujo.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RemapOamTile&amp;lt;/code&amp;gt; || Ajusta el número de tile para utilizar la ubicación real de los gráficos dinámicos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!IsValid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!XIsValid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!YIsValid&amp;lt;/code&amp;gt; || Comprobaciones utilizadas por el dibujo para decidir si un tile puede mostrarse.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!AssignPalette&amp;lt;/code&amp;gt; || Selecciona el destino de una paleta según el modo de asignación.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!LoadPaletteOnBuffer&amp;lt;/code&amp;gt; || Carga datos de paleta en un espacio de trabajo para procesarlos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!SetRGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!SetHSLBase&amp;lt;/code&amp;gt; || Prepara los colores para calcular efectos RGB o HSL.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RGBToHSL&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!HSLToRGB&amp;lt;/code&amp;gt; || Convierte entre ambos sistemas de color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!RGBMerge&amp;lt;/code&amp;gt; || Convierte colores RGB separados al formato de paleta de SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!Mix...&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!MixAndMerge...&amp;lt;/code&amp;gt; || Aplica cambios a uno o varios componentes del color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalTransitionRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PalTransitionHSL&amp;lt;/code&amp;gt; || Calcula el cambio de una paleta a otra.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalTransitionAndMergeRGB&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!PalTransitionAndMergeHSL&amp;lt;/code&amp;gt; || Calcula la transición y deja el resultado en formato de SNES.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!DoEffect&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;!DoEffectAndMerge&amp;lt;/code&amp;gt; || Aplica un efecto mediante su ID.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!PalFunctionRGB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PalFunctionHSL&amp;lt;/code&amp;gt; y variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Nombres reservados para funciones de color que todavía no están implementadas.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Routines&amp;lt;/code&amp;gt; es la dirección de la tabla desde la que se obtienen estas llamadas. No necesitas calcular sus posiciones para usar los defines publicados.&lt;br /&gt;
&lt;br /&gt;
== Rutinas para sprites ==&lt;br /&gt;
&lt;br /&gt;
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: &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt;. La ruta del include es relativa al archivo ASM del sprite.&lt;br /&gt;
&lt;br /&gt;
Para usar llamadas como &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, escribe su nombre directamente, como muestran los ejemplos. No añadas &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt; delante. Salvo que se indique lo contrario, X debe contener el número del slot que ocupa el sprite.&lt;br /&gt;
&lt;br /&gt;
=== RenderBox ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; 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).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen,x&amp;lt;/code&amp;gt;: distancias horizontal y vertical permitidas fuera de la pantalla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite está en pantalla o dentro de la distancia permitida fuera de sus bordes; se debe ejecutar la long routine.&lt;br /&gt;
* Carry desactivado: el sprite está demasiado lejos de la pantalla para dibujarse; se debe ejecutar la short routine.&lt;br /&gt;
&lt;br /&gt;
Cuando el sprite está demasiado lejos, establece &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Esto indica que deberá volver a obtener su paleta y su pose cuando se acerque a la pantalla. También guarda en &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt; el volteo que resulta de combinar &amp;lt;code&amp;gt;!GlobalFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip&amp;lt;/code&amp;gt;. En sprites normales actualiza además las variables que indican si está fuera de pantalla horizontal o verticalmente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
print &amp;quot;INIT &amp;quot;,pc&lt;br /&gt;
    LDA.b #!RenderBoxXDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderXDistanceOutOfScreen,x&lt;br /&gt;
    LDA.b #!RenderBoxYDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderYDistanceOutOfScreen,x&lt;br /&gt;
    ; Aquí va el resto de la inicialización del sprite&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
SpriteCode:&lt;br /&gt;
    !RenderBox&lt;br /&gt;
    BCS .LongRoutine&lt;br /&gt;
&lt;br /&gt;
.ShortRoutine&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    %SubOffScreen()&lt;br /&gt;
    ; Aquí va la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&lt;br /&gt;
.LongRoutine&lt;br /&gt;
    ; Aquí van el manejo de paletas, poses y dibujo&lt;br /&gt;
    ; y la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La llamada a &amp;lt;code&amp;gt;%SubOffScreen()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; se generan desde el DrawInfo y se guardan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. 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, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Si el sprite utiliza varios DrawInfo, utiliza la mayor distancia horizontal y la mayor distancia vertical entre ellos.&lt;br /&gt;
&lt;br /&gt;
=== PaletteAssignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; selecciona una paleta del DynamicInfo usando &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
Si el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; está activado (&amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;), también procesa los efectos globales de paleta correspondientes. Si está desactivado, la paleta queda excluida del efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cómo se elige la paleta&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; indica qué paleta de sprites se permite utilizar y si sus colores reciben el efecto global. Su formato es &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt;: 0 excluye la paleta del efecto global; 1 permite aplicarlo.&lt;br /&gt;
* &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt;: con asignación manual, selecciona una paleta entre 8 y F. &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; elige la 8, &amp;lt;code&amp;gt;001&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* Con asignación automática, &amp;lt;code&amp;gt;PPP = 000&amp;lt;/code&amp;gt; permite buscar entre las ocho paletas. Un valor &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; limita la búsqueda a las paletas 8-B; un valor &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; la limita a las C-F.&lt;br /&gt;
* Los cuatro bits bajos no se utilizan para estas opciones.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; decide quién elige el destino y si se cargan colores. Su formato es &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 00&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;): automático. Dynamic Xtreme elige una de las paletas permitidas y carga los colores del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 01&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;): manual. Utiliza la paleta indicada en &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; y carga los colores del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 10&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;): manual sin carga. Utiliza la paleta indicada en &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; con los colores que ya tiene el nivel.&lt;br /&gt;
&lt;br /&gt;
En sprites normales, &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; es &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; es &amp;lt;code&amp;gt;!ExtraProp2,x&amp;lt;/code&amp;gt;. Lo habitual es usar el primer Extra Byte con formato &amp;lt;code&amp;gt;EPPPVVVV&amp;lt;/code&amp;gt; y copiar sus cuatro bits bajos a &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, con asignación manual, &amp;lt;code&amp;gt;!PaletteOption,x = $A0&amp;lt;/code&amp;gt; utiliza la paleta A y permite el efecto global. Si &amp;lt;code&amp;gt;!Version,x = 1&amp;lt;/code&amp;gt;, carga en ella la segunda paleta de la lista del DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; correspondiente al DynamicInfo que contiene las paletas.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;: índice de la paleta dentro de la tabla.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: última versión procesada. Se compara con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; para detectar cambios y debe inicializarse en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;: selección de paleta y participación en el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt;: asignación automática, manual o manual sin carga.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite puede dibujarse con la paleta asignada.&lt;br /&gt;
* Carry desactivado: el sprite todavía no tiene una paleta lista para dibujar.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta asignada, con valores de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos para las paletas 8-F.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: se actualiza con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; cuando se procesa la nueva asignación.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignment&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre del recurso se normaliza en PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== PaletteAssignmentNoUpload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; elige la paleta igual que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
El bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;) 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 &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; elige la paleta del DynamicInfo: 0 para la primera, 1 para la segunda, etc. &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: 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, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; elige el destino automáticamente, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; usa el indicado en PPP y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt;: mismas opciones que en &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: última versión procesada, utilizada para detectar cambios respecto de &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;. Debe inicializarse en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite tiene una paleta asignada; desactivado si no pudo obtenerse.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta asignada.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: se actualiza con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; cuando se procesa la nueva asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: número que identifica la paleta elegida del DynamicInfo, cuando se utiliza un modo que carga sus colores.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base en ROM.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    ; Aquí se prepara y concatena el efecto.&lt;br /&gt;
    ; Conserva Y y la dirección de $02-$04 para esa llamada.&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; dice qué paleta del DynamicInfo se eligió; &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; dice cuál de las paletas 8-F utilizará el sprite para dibujarse. Los datos de &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;, eliminando los separadores.&lt;br /&gt;
&lt;br /&gt;
=== Upload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; consigue los gráficos de la pose que el sprite quiere mostrar. La pose se selecciona sumando &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico base.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt;: índice que se suma al ID base.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt;: volteos que se combinarán para dibujar.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* Carry desactivado: el sprite todavía no tiene una pose disponible.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt;: estado de la pose disponible para dibujar.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    !Upload&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== UploadWithoutPoseOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; solicita directamente el ID dinámico entregado en A, sin sumarle &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;. Como &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, reutiliza los gráficos si ya están en VRAM y puede seguir mostrando la pose anterior mientras no consiga cargar la nueva.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: existe &amp;lt;code&amp;gt;%DXExtendedUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;, pero actualmente &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; no publica el alias &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico exacto.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt;: volteos del sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite tiene una pose disponible para dibujar; desactivado si todavía no tiene ninguna.&lt;br /&gt;
* Guarda la pose que se puede dibujar en &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt; y la ubicación de sus gráficos en &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;, igual que &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite003&lt;br /&gt;
    !UploadWithoutPoseOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite003&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== DXDraw ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; dibuja una pose utilizando los gráficos dinámicos disponibles para el sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID de la pose de dibujo.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;): propiedades adicionales, con formato &amp;lt;code&amp;gt;YXCC----&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;): prioridad máxima de los tiles; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; máxima, &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; alta, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; propia del tipo de sprite y &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; mínima.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;: paleta, volteo y ubicación de los gráficos disponibles.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose en pantalla. Si &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no dibuja. A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDraw&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, las poses deben estar en el mismo orden en el DrawInfo y el DynamicInfo. Se utiliza &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; porque indica qué pose se puede dibujar: si la nueva todavía no se pudo cargar, seguirá mostrando la anterior.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres de recurso y pose se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Este ID de dibujo es distinto de los IDs &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; del DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
=== DXDrawWithOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Las mismas entradas de &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;): desplazamiento horizontal de 8 bits con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;): desplazamiento vertical de 8 bits con signo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja igual que &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;, pero suma los desplazamientos que preparaste. Un valor positivo en &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; mueve el dibujo a la derecha; en &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt;, hacia abajo. Los valores negativos lo mueven a la izquierda o hacia arriba.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$08&lt;br /&gt;
    STA !XOffsetParam&lt;br /&gt;
    LDA #$F8&lt;br /&gt;
    STA !YOffsetParam&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDrawWithOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo desplaza el dibujo 8 píxeles a la derecha y 8 hacia arriba. &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; el nombre se normaliza en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ReplacePalette ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Suele utilizarse después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;: primero se asigna la paleta sin cargar sus colores y después se reemplazan por los que quieres mostrar. Antes de llamar a &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, coloca en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; la dirección de los nuevos colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* A en modo de 8 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de la nueva paleta en BGR555.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta ya asignada.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;: participación en el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta; si los nuevos colores todavía no están listos, se conservan los anteriores.&lt;br /&gt;
* Carry desactivado: la paleta todavía no tiene colores listos para dibujar.&lt;br /&gt;
&lt;br /&gt;
Mantiene el mismo ID de paleta, pero solicita cambiar sus colores. Al marcar que el efecto debe volver a calcularse, utiliza &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; si nunca se habían obtenido colores para dibujar, o &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; si puede seguir mostrando los anteriores mientras prepara los nuevos.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ReplaceSpritePalette:&lt;br /&gt;
    ; Ejecutar cuando se necesite cambiar una paleta ya asignada.&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;8&lt;br /&gt;
    STA $03&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
    !ReplacePalette&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyAlternatePalette&amp;lt;/code&amp;gt; es la dirección de una paleta insertada desde los recursos declarados en un DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_alternate_palette&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyAlternatePalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ConcatenateRGBPaletteEffectToGlobal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, y después aplica el global sobre ese resultado. Llámala después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, que deja preparada la paleta original.&lt;br /&gt;
&lt;br /&gt;
El uso habitual es asignar primero la paleta con &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; y, si el carry está activado, llamar a esta rutina para aplicar los efectos y completar la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID del efecto local RGB.&lt;br /&gt;
* X de 8 bits: copia aquí el valor de &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;LDA !Palette,x&amp;lt;/code&amp;gt; seguido de &amp;lt;code&amp;gt;TAX&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
* Y de 8 bits: conserva el valor que dejó &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;. El valor 1 obliga a calcular de nuevo el efecto; 0 permite reutilizar el resultado anterior si no cambió nada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base BGR555 preparada por la asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;: el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; debe estar activado para combinar con el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta. Si el nuevo efecto todavía no está listo, se sigue mostrando el anterior.&lt;br /&gt;
* Carry desactivado: todavía no hay colores listos para dibujar esa paleta.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyRGBEffect0&lt;br /&gt;
    !ConcatenateRGBPaletteEffectToGlobal&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y &amp;lt;code&amp;gt;!PaletteEffectIDMyRGBEffect0&amp;lt;/code&amp;gt; desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. Ambos quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Si se necesita Y para seleccionar el efecto mediante una tabla, conserva su valor con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; y restáuralo con &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; antes de concatenar.&lt;br /&gt;
&lt;br /&gt;
=== ConcatenateHSLPaletteEffectToGlobal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt; permite que la paleta del sprite tenga un efecto HSL propio, como &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, y siga siendo afectada por el efecto global. Primero aplica el efecto local y después el global. Llámala después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, que deja preparada la paleta original.&lt;br /&gt;
&lt;br /&gt;
El uso habitual es asignar primero la paleta con &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; y, si el carry está activado, llamar a esta rutina para aplicar los efectos y completar la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID del efecto local HSL.&lt;br /&gt;
* X de 8 bits: copia aquí el valor de &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;LDA !Palette,x&amp;lt;/code&amp;gt; seguido de &amp;lt;code&amp;gt;TAX&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
* Y de 8 bits: conserva el valor que dejó &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;. El valor 1 obliga a calcular de nuevo el efecto; 0 permite reutilizar el resultado anterior si no cambió nada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base BGR555 preparada por la asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;: el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; debe estar activado para combinar con el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta. Si el nuevo efecto todavía no está listo, se sigue mostrando el anterior.&lt;br /&gt;
* Carry desactivado: todavía no hay colores listos para dibujar esa paleta.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyHSLEffect0&lt;br /&gt;
    !ConcatenateHSLPaletteEffectToGlobal&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y &amp;lt;code&amp;gt;!PaletteEffectIDMyHSLEffect0&amp;lt;/code&amp;gt; desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. Quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y utilizan nombres normalizados en PascalCase: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra. Conserva Y con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; si lo utilizas temporalmente para seleccionar el efecto.&lt;br /&gt;
&lt;br /&gt;
Ambas variantes de concatenación realizan las conversiones necesarias si el efecto local y el global utilizan espacios de color diferentes. Consulta [[es/Dynamic_Xtreme_files_and_formats#Tipos_de_efectos|Tipos de efectos]] para identificar los efectos RGB y HSL.&lt;br /&gt;
&lt;br /&gt;
== Rutinas y Macros Generales ==&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!NormalPoseIndex,x&amp;lt;/code&amp;gt;, escríbelo entre comillas para que Asar lo lea como un solo argumento. Utiliza &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; al entregar un valor inmediato, como &amp;lt;code&amp;gt;#$04&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Poses dinámicas ===&lt;br /&gt;
&lt;br /&gt;
==== DynamicPoseSpaceConfig ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; elige qué partes de la memoria gráfica (VRAM) puede usar Dynamic Xtreme para cargar poses dinámicas. Normalmente se llama desde el &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; de UberASM al entrar al nivel.&lt;br /&gt;
&lt;br /&gt;
Los defines con las configuraciones disponibles se encuentran en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, bajo los nombres &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 8 bits: una de las configuraciones &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus valores van de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicSpaceConfigSP4&amp;lt;/code&amp;gt; es una constante publicada en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permite utilizar SP4. Otras opciones incluyen &amp;lt;code&amp;gt;!DynamicSpaceConfigSP3&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt;. Selecciona una región que no se superponga con los gráficos estáticos utilizados por el nivel.&lt;br /&gt;
&lt;br /&gt;
==== TakeDynamicRequest ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !TakeDynamicRequest&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Y de 16 bits: ID exacto de la pose dinámica.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RequestPose:&lt;br /&gt;
    REP #$10&lt;br /&gt;
    LDY #!DynamicPoseIDMySprite000&lt;br /&gt;
    JSL !TakeDynamicRequest&lt;br /&gt;
    BCC .Unavailable&lt;br /&gt;
&lt;br /&gt;
    ; X contiene el índice hash de la pose solicitada.&lt;br /&gt;
    ; Aquí tu código puede guardar ese índice para dibujar la pose.&lt;br /&gt;
RTS&lt;br /&gt;
.Unavailable&lt;br /&gt;
    ; Aquí se maneja la falta de recursos.&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores y escribiendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== DynamicRoutine ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !DynamicRoutine&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; prepara esos datos antes de llamarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Datos que necesita la llamada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt;: variable interna de 16 bits que contiene el ID de la pose que se va a copiar.&lt;br /&gt;
* 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.&lt;br /&gt;
&lt;br /&gt;
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. &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; realiza ambas tareas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo de funcionamiento&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Cuando un sprite solicita una pose que todavía no está en VRAM, &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; busca dónde colocarla. Después guarda su ID en &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt; y llama a &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; con la posición elegida en A. Esta última prepara la copia de los gráficos; el NMI ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
Para cargar una pose desde el código de un sprite, utiliza &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. Si necesitas hacer la solicitud directamente mediante su ID, utiliza &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt;. Llamar a &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; requiere preparar también la variable interna del ID, el banco de datos y el espacio de destino descritos arriba.&lt;br /&gt;
&lt;br /&gt;
==== GeneralUpload ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%GeneralUpload(Pose16, checkLast, sprite, flip, safeCheck, withoutOffset,&lt;br /&gt;
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,&lt;br /&gt;
    globalFlip, localFlip, lastFlip)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La firma anterior muestra el orden de los parámetros; escribe la llamada en una sola línea.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Pose16&amp;lt;/code&amp;gt;: 0 utiliza índices de pose de 8 bits; 1 utiliza índices de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt;: 1 permite seguir dibujando la pose anterior si no se pudo obtener la nueva; 0 desactiva esa opción.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 0 para usar variables propias sin recuperar el índice del sprite; 1 para trabajar con las tablas del sprite, recuperando X desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 2 funciona como 1, pero solicita la pose sin comparar ni cambiar &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;flip&amp;lt;/code&amp;gt;: 1 combina &amp;lt;code&amp;gt;globalFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;localFlip&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;; 0 omite esa actualización.&lt;br /&gt;
* &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt;: 1 evita repetir la solicitud en el mismo frame utilizando &amp;lt;code&amp;gt;safeLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;safeHigh&amp;lt;/code&amp;gt;; 0 omite la comprobación.&lt;br /&gt;
* &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;: 0 suma &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt; al ID base; 1 utiliza directamente el ID recibido.&lt;br /&gt;
* &amp;lt;code&amp;gt;safeLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;safeHigh&amp;lt;/code&amp;gt;: variables que guardan los bytes bajo y alto del frame de la solicitud. Se escriben incluso cuando &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; es 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt;: variable del índice de pose deseado.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;: variable del último índice de pose disponible.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;: variable que identifica la entrada donde Dynamic Xtreme guarda la ubicación de los gráficos en VRAM. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; indica que todavía no hay gráficos disponibles.&lt;br /&gt;
* &amp;lt;code&amp;gt;globalFlip&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;localFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variables del volteo global, local y efectivo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada adicional&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico base o exacto, según &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Para &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; debe contener el índice del sprite.&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt;, la macro solicita la pose aunque &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sean iguales, y deja &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sin modificar. Si consigue los gráficos, guarda su ubicación en &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;. Si la solicitud falla y &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; es 1, puede seguir usando los gráficos anteriores. &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; sigue controlando si se permite repetir la solicitud durante el mismo frame.&lt;br /&gt;
&lt;br /&gt;
Este valor 2 no cambia el tamaño de los índices. Para utilizar variables de índice de 16 bits se selecciona &amp;lt;code&amp;gt;Pose16 = 1&amp;lt;/code&amp;gt;. El ID dinámico entregado en A siempre es de 16 bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Devuelve el carry activado cuando hay una pose disponible para dibujar: la solicitada o la anterior si &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; al final; colócala al final de una rutina llamada con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %GeneralUpload(0, 1, 1, 1, 1, 0, &amp;quot;!NormalSafeFrameLowByte,x&amp;quot;, &amp;quot;!NormalSafeFrameHighByte,x&amp;quot;, &amp;quot;!NormalPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalGlobalFlip,x&amp;quot;, &amp;quot;!NormalLocalFlip,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las tablas de un sprite normal y un índice de pose de 8 bits. &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; el nombre se normaliza en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Upload (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%Upload()&amp;lt;/code&amp;gt; es la variante de &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; para índices de pose de 8 bits. No debe confundirse con el alias para sprites &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Upload(sprite, checkLast, flip, safeCheck, withoutOffset,&lt;br /&gt;
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,&lt;br /&gt;
    globalFlip, localFlip, lastFlip)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Recibe los mismos datos que &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt;, pero los índices guardados en las variables siempre son de 8 bits. La macro ya incluye el &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
El parámetro &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt; también admite 2: omite la comparación con &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; y no actualiza esa variable, pero sí actualiza &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt; al obtener la pose. No habilita índices de 16 bits; para eso se utiliza &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;Pose16 = 1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sin modificar, el código del sprite puede controlar ese cambio.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %Upload(1, 1, 1, 1, 0, &amp;quot;!NormalSafeFrameLowByte,x&amp;quot;, &amp;quot;!NormalSafeFrameHighByte,x&amp;quot;, &amp;quot;!NormalPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalGlobalFlip,x&amp;quot;, &amp;quot;!NormalLocalFlip,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; es generado desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpriteUpload ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpriteUpload(withoutOffset, type)&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;: 0 suma &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; al ID base; 1 utiliza el ID exacto.&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A de 16 bits: ID dinámico.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* Tablas de poses y volteo de Dynamic Xtreme del tipo seleccionado, inicializadas como en las rutinas &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %StandardSpriteUpload(0, &amp;quot;Normal&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;, eliminando los separadores.&lt;br /&gt;
&lt;br /&gt;
=== Dibujo de poses ===&lt;br /&gt;
&lt;br /&gt;
Las macros de esta categoría terminan la rutina que las contiene mediante &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;. Los ejemplos deben llamarse con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;. A debe contener el ID de dibujo con 16 bits; &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;) se preparan igual que para &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Draw ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%Draw()&amp;lt;/code&amp;gt; dibuja una pose dinámica. En la llamada indicas qué gráficos usar, su paleta, su volteo y la posición donde quieres dibujarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Draw(offset, sprite, lastPoseHashIndex, lastFlip, palette, xl, xh, yl, yh)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 utiliza las coordenadas entregadas; 1 añade &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;), de 8 bits con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 recupera el índice del sprite en X desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; antes de leer su paleta y posición; 0 omite ese paso.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;: variable que identifica dónde están registrados los gráficos de la pose en Dynamic Xtreme. Si contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no se dibuja.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variable o valor que indica el volteo con el que se dibujará.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de la paleta; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; selecciona la 8, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* &amp;lt;code&amp;gt;xl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;xh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición X.&lt;br /&gt;
* &amp;lt;code&amp;gt;yl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;yh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose con los gráficos indicados por &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMySprite_Frame0&lt;br /&gt;
    %Draw(0, 1, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. El ID debe corresponder a los gráficos dinámicos disponibles.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpriteDraw ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpriteDraw(offset, type)&amp;lt;/code&amp;gt; dibuja una pose dinámica utilizando las tablas de Dynamic Xtreme del tipo de sprite seleccionado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 sin desplazamiento adicional; 1 utiliza los offsets de &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A de 16 bits: ID de dibujo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt;: propiedades y prioridad.&lt;br /&gt;
* Las tablas de paleta, último volteo e índice hash de Dynamic Xtreme del tipo seleccionado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;%Draw()&amp;lt;/code&amp;gt;, utilizando las tablas estándar. Es la macro que utilizan las rutinas PIXI &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para sprites normales, las rutinas PIXI preparan los aliases de coordenadas &amp;lt;code&amp;gt;!NormalXLow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!NormalXHigh&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!NormalYLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!NormalYHigh&amp;lt;/code&amp;gt;. Si se expande la macro directamente, también deben estar definidos, como en este ejemplo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!NormalXLow = !SpriteXLow&lt;br /&gt;
!NormalXHigh = !SpriteXHigh&lt;br /&gt;
!NormalYLow = !SpriteYLow&lt;br /&gt;
!NormalYHigh = !SpriteYHigh&lt;br /&gt;
&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMySprite_Frame0&lt;br /&gt;
    %StandardSpriteDraw(0, &amp;quot;Normal&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== DrawStatic ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt; dibuja una pose estática, declarada con &amp;lt;code&amp;gt;.IsStatic&amp;lt;/code&amp;gt; en el DrawInfo. Sus gráficos deben estar previamente cargados en las posiciones de VRAM indicadas por sus tiles.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%DrawStatic(offset, sprite, lastFlip, palette, xl, xh, yl, yh)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 sin desplazamiento adicional; 1 utiliza &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;), con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: parámetro conservado en la firma; la implementación actual de esta macro no lo utiliza.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variable o valor que indica el volteo; &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; dibuja sin volteo.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de paleta: &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; selecciona la 8, &amp;lt;code&amp;gt;#$02&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;#$0E&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* &amp;lt;code&amp;gt;xl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;xh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición X.&lt;br /&gt;
* &amp;lt;code&amp;gt;yl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;yh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas adicionales&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID de dibujo estático.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;): propiedades y prioridad.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;): 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose sin consultar la caché de gráficos dinámicos. No requiere &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; ni una llamada previa a &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$80&lt;br /&gt;
    STA !Tile&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMyStaticSprite_Frame0&lt;br /&gt;
    %DrawStatic(0, 1, #$00, #$04, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza el tile &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; si la pose está configurada para tomarlo desde &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, sin volteo y con la paleta A. &amp;lt;code&amp;gt;!PoseIDMyStaticSprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_static_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyStaticSprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Paletas ===&lt;br /&gt;
&lt;br /&gt;
Estas macros permiten elegir qué paleta usa un sprite, cargar sus colores y cambiarlos durante el juego.&lt;br /&gt;
&lt;br /&gt;
==== LoadPaletteIDAndAddress ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%LoadPaletteIDAndAddress()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 8 bits: índice de la paleta dentro del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt;: guarda aquí el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; de tu DynamicInfo, con 16 bits, como muestra el ejemplo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: ID de la paleta.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de sus colores en ROM, en formato BGR555.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    STA $0E&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    LDA #$01            ; Segunda paleta del DynamicInfo&lt;br /&gt;
    %LoadPaletteIDAndAddress()&lt;br /&gt;
    ; $00-$01 contiene su ID y $02-$04 su dirección ROM.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En PIXI también puede llamarse mediante &amp;lt;code&amp;gt;%DXLoadPaletteIDAndAddress()&amp;lt;/code&amp;gt;, con las mismas entradas y resultados. Esta variante llama a una rutina compartida y después continúa con el código siguiente.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones bajos y guiones, y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignment (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt; asigna y carga una paleta igual que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
Si la paleta ya estaba asignada, mantiene su temporizador de uso en 2 para que no sea reemplazada mientras se utiliza. Si el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; de las opciones está activado, también aplica el efecto global correspondiente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteAssignment(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 utiliza &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; para acceder a las tablas del sprite; 0 permite usar variables independientes del índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable que recibe la paleta asignada. Debe comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Los valores &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, ..., &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; corresponden a las paletas 8-F.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteAssignment&amp;lt;/code&amp;gt;: variable o valor con formato &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; permite que Dynamic Xtreme elija el destino y cargue los colores; &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; utiliza el destino que tú indicas y carga los colores; &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; utiliza ese destino con los colores que ya tiene el nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor con formato &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;. E = 1 permite aplicar el efecto global; E = 0 lo excluye. En modo manual, PPP elige entre la paleta 8 (&amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt;) y la F (&amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt;). En automático, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F. Los cuatro bits bajos no se usan para estas opciones.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteVersion&amp;lt;/code&amp;gt;: 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 &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt;: variable que guarda la última versión procesada. Debe comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualIDGroup&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt;: juntos forman el número con el que el sistema reconoce la paleta en los modos manuales. El primero indica el grupo: &amp;lt;code&amp;gt;#$FE&amp;lt;/code&amp;gt; para normal, &amp;lt;code&amp;gt;#$FC&amp;lt;/code&amp;gt; para cluster y &amp;lt;code&amp;gt;#$FD&amp;lt;/code&amp;gt; para extended. El segundo indica el tipo de sprite; en uno normal se utiliza &amp;lt;code&amp;gt;!CustomSpriteNumber,x&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
&lt;br /&gt;
También puedes crear grupos propios: por ejemplo, usar &amp;lt;code&amp;gt;manualIDGroup = #$FB&amp;lt;/code&amp;gt; para el jugador y &amp;lt;code&amp;gt;#$FA&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt; para distinguir los recursos dentro de cada uno. Los grupos &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$FD&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FC&amp;lt;/code&amp;gt; ya son utilizados por las rutinas de sprites normales, extended y cluster, respectivamente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada adicional&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* Si &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; debe contener el índice del sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: hay una paleta con la que se puede dibujar; desactivado si todavía no hay ninguna.&lt;br /&gt;
* Guarda el número de paleta en &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt; y actualiza &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt; cuando procesa la versión.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %PaletteAssignment(1, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!NormalPaletteAssignment,x&amp;quot;, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalVersion,x&amp;quot;, &amp;quot;!NormalLastVersion,x&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las variables de un sprite normal. &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; que termina la rutina, por lo que no debes añadir código después de ella.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignmentNoUpload (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; elige una paleta como &amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt;, pero deja pendiente la carga de sus colores. Permite aplicar después un efecto local y combinarlo con el global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteAssignmentNoUpload(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los parámetros son los mismos que en &amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt;. A recibe el offset de la tabla con 16 bits. &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt; deben comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;paletteVersion&amp;lt;/code&amp;gt; elige los colores de la lista del DynamicInfo: 0 para la primera paleta, 1 para la segunda, etc. &amp;lt;code&amp;gt;paletteAssignment&amp;lt;/code&amp;gt; decide el modo: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; automático, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; manual y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; manual sin cargar colores. &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: E permite el efecto global y PPP selecciona la paleta 8-F en manual. En automático, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F. Para aplicar después un efecto local sobre los colores del DynamicInfo, utiliza el modo automático o manual con carga.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: hay una paleta asignada; desactivado si no pudo obtenerse.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: número de la paleta asignada, de dos en dos entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt;: última versión procesada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: ID de la paleta seleccionada del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de sus colores.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
Usa los datos de &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
AssignPaletteForEffect:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %PaletteAssignmentNoUpload(1, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!NormalPaletteAssignment,x&amp;quot;, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalVersion,x&amp;quot;, &amp;quot;!NormalLastVersion,x&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Después de llamar a &amp;lt;code&amp;gt;AssignPaletteForEffect&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;, comprueba el carry y aplica el efecto usando los datos devueltos. Conserva Y y &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; para la llamada de concatenación.&lt;br /&gt;
&lt;br /&gt;
La macro ya termina la rutina con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. El código que aplica el efecto va después de la llamada &amp;lt;code&amp;gt;JSL AssignPaletteForEffect&amp;lt;/code&amp;gt;, no después de la macro dentro de esa rutina.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpritePaletteAssignment ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpritePaletteAssignment()&amp;lt;/code&amp;gt; utiliza las variables de paleta del tipo de sprite indicado. Es la macro utilizada por las rutinas PIXI de asignación.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%StandardSpritePaletteAssignment(type, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualIDGroup&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;#$FE&amp;lt;/code&amp;gt; para normal, &amp;lt;code&amp;gt;#$FC&amp;lt;/code&amp;gt; para cluster o &amp;lt;code&amp;gt;#$FD&amp;lt;/code&amp;gt; para extended.&lt;br /&gt;
* También puedes elegir un grupo propio, por ejemplo &amp;lt;code&amp;gt;#$FB&amp;lt;/code&amp;gt; para el jugador o &amp;lt;code&amp;gt;#$FA&amp;lt;/code&amp;gt; para otro tipo de entidad, siempre que esos valores no estén siendo utilizados por otro grupo de tu proyecto.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt;: variable o valor que identifica el tipo de sprite en los modos manuales.&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* Las variables de Dynamic Xtreme para paleta, opciones, versión y última versión del tipo seleccionado, preparadas como en &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;: guarda la paleta asignada en la tabla del sprite y devuelve el carry activado cuando se puede dibujar con ella.&lt;br /&gt;
&lt;br /&gt;
La macro ya incluye un &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt; y no añadas código después de la macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %StandardSpritePaletteAssignment(&amp;quot;Normal&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt; al eliminar los separadores.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpritePaletteAssignmentNoUpload ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpritePaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; utiliza las variables del tipo de sprite seleccionado para asignar la paleta, dejando pendiente la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%StandardSpritePaletteAssignmentNoUpload(type, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Recibe los mismos parámetros y datos que &amp;lt;code&amp;gt;%StandardSpritePaletteAssignment()&amp;lt;/code&amp;gt;. A debe contener el offset de la tabla de paletas con 16 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;: guarda la paleta asignada y devuelve el carry, Y, el ID en &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; y la dirección en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;, con las condiciones indicadas en esa entrada.&lt;br /&gt;
&lt;br /&gt;
La macro ya incluye un &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL AssignPaletteForEffect&amp;lt;/code&amp;gt;. El código que aplica el efecto va después de esa llamada.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
AssignPaletteForEffect:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %StandardSpritePaletteAssignmentNoUpload(&amp;quot;Normal&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== ReplacePalette (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ReplacePalette()&amp;lt;/code&amp;gt; sustituye los colores de una paleta que ya estás usando. Hace lo mismo que &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, pero tú eliges qué variables leer. Si otros sprites o códigos usan esa misma paleta, también verán los nuevos colores.&lt;br /&gt;
&lt;br /&gt;
Suele utilizarse después de una asignación sin carga, como &amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;. Primero obtienes la paleta asignada y después preparas en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; la dirección de los colores que quieres usar para reemplazarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%ReplacePalette(sprite, paletteOption, palette)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 obtiene el índice del sprite desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 0 utiliza variables independientes de ese índice.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor de las opciones de paleta. El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica si se aplica el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de la paleta de destino, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de los nuevos colores en BGR555.&lt;br /&gt;
* A en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Llámala cuando cambien los colores que quieres mostrar. Repetir la llamada cada frame obliga a preparar de nuevo la paleta y sus efectos.&lt;br /&gt;
&lt;br /&gt;
Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL ReplaceSpritePalette&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
ReplaceSpritePalette:&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;8&lt;br /&gt;
    STA $03&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
    %ReplacePalette(1, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyAlternatePalette&amp;lt;/code&amp;gt; es la dirección de una paleta insertada a partir de los recursos del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_alternate_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyAlternatePalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Efectos de paleta ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 [[es/Dynamic_Xtreme_files_and_formats#Tipos_de_efectos|Tipos de efectos]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;¿Qué llamada necesitas?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Quieres… !! Utiliza…&lt;br /&gt;
|-&lt;br /&gt;
| Teñir una paleta o cambiar su tono, saturación o luminosidad. || &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MixAndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Pasar de una paleta a otra. || &amp;lt;code&amp;gt;PaletteTransition&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Aplicar un efecto que ya definiste en un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. || &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DoEffectAndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Darle un efecto propio a un sprite y conservar además el efecto global. || &amp;lt;code&amp;gt;ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; o su variante HSL, después de asignar la paleta sin carga.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para calcular un efecto directamente, el proceso habitual es preparar los colores originales con &amp;lt;code&amp;gt;SetRGBBase&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;SetHSLBase&amp;lt;/code&amp;gt; y después aplicar el cambio. Los ejemplos utilizan las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt;, que trabajan con las copias de paleta de Dynamic Xtreme y evitan escribir direcciones de memoria.&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, estas ya se encargan de preparar los colores y completar su carga.&lt;br /&gt;
&lt;br /&gt;
En los ejemplos, prepara A en modo de 8 bits antes de llamar a las macros.&lt;br /&gt;
&lt;br /&gt;
==== Preparar los colores: SetRGBBase y SetHSLBase ====&lt;br /&gt;
&lt;br /&gt;
Antes de modificar los colores, necesitas una copia con la que calcular el efecto. &amp;lt;code&amp;gt;%SetRGBBase()&amp;lt;/code&amp;gt; prepara esa copia para efectos RGB; &amp;lt;code&amp;gt;%SetHSLBase()&amp;lt;/code&amp;gt; la prepara para HSL. Si los colores originales no cambiaron, puedes reutilizarla en los siguientes frames.&lt;br /&gt;
&lt;br /&gt;
En las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; solo indicas el primer color y cuántos colores quieres preparar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%SetRGBBaseDefault(offset, length)&lt;br /&gt;
%SetHSLBaseDefault(offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; es el número del primer color y &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; es la cantidad. Por ejemplo, &amp;lt;code&amp;gt;#$0081&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;#$000F&amp;lt;/code&amp;gt; seleccionan los 15 colores visibles de la paleta 8.&lt;br /&gt;
&lt;br /&gt;
Si necesitas elegir tú las direcciones donde leer y guardar los colores, utiliza las versiones completas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%SetRGBBase(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%SetHSLBase(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;%SetRGBBaseDefault(offset, length)&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%SetHSLBaseDefault(offset, length)&amp;lt;/code&amp;gt; leen de &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; y guardan el resultado en &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: preparar una paleta de sprites&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Paleta 8, sin incluir su primer color transparente.&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
    ; Para trabajar en HSL, utiliza esta variante en su lugar:&lt;br /&gt;
    ; %SetHSLBaseDefault(#$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$81&amp;lt;/code&amp;gt; es el segundo color de la paleta 8: la paleta comienza en el color &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; y se procesan los 15 siguientes.&lt;br /&gt;
&lt;br /&gt;
==== Mezclar colores: Mix y MixAndMerge ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Los parámetros &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; indican el color que quieres alcanzar, entre 0 y 31. Los parámetros &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#$7F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para RGB, los valores 1, 2 y 3 corresponden a rojo, verde y azul. Para HSL corresponden a tono, saturación y luminosidad.&lt;br /&gt;
&lt;br /&gt;
El final del nombre indica qué componentes se modifican:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! RGB !! HSL !! Componentes modificados&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;H&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;L&amp;lt;/code&amp;gt; || Uno.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GB&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SL&amp;lt;/code&amp;gt; || Dos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RGB&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HSL&amp;lt;/code&amp;gt; || Los tres.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada combinación está disponible como &amp;lt;code&amp;gt;Mix...&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixAndMerge...&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;MixAndMerge...Default&amp;lt;/code&amp;gt;. Por ejemplo: &amp;lt;code&amp;gt;%MixR()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%MixAndMergeR()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%MixAndMergeRDefault()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; omiten las direcciones.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%MixRGB(r1, r2, r3, v1, v2, v3, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%MixAndMergeRG(r1, r2, v1, v2, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%MixAndMergeLDefault(r3, v3, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo RGB: teñir de rojo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; Preparar los colores originales de la paleta 8.&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
    ; Acercar los tres componentes a un rojo puro, aproximadamente a la mitad.&lt;br /&gt;
    %MixAndMergeRGBDefault(#$40, #$40, #$40, #$1F, #$00, #$00, #$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los tres primeros valores &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt; indican la intensidad del cambio para rojo, verde y azul. Los siguientes, &amp;lt;code&amp;gt;#$1F, #$00, #$00&amp;lt;/code&amp;gt;, indican el rojo puro al que se acercarán. Los dos últimos seleccionan los 15 colores de la paleta 8.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo HSL: aclarar la paleta&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %SetHSLBaseDefault(#$0081, #$000F)&lt;br /&gt;
    %MixAndMergeLDefault(#$40, #$1F, #$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aquí solo cambia la luminosidad: &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt; aplica aproximadamente la mitad del cambio y &amp;lt;code&amp;gt;#$1F&amp;lt;/code&amp;gt; indica la luminosidad máxima. Este es un ejemplo independiente del anterior.&lt;br /&gt;
&lt;br /&gt;
==== Cambiar entre paletas: PaletteTransition ====&lt;br /&gt;
&lt;br /&gt;
Estas macros acercan cada color de la paleta original al color correspondiente de otra paleta. A diferencia de &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt;, cada color tiene su propio destino. Sirven, por ejemplo, para pasar de los colores normales de un sprite a una paleta de daño.&lt;br /&gt;
&lt;br /&gt;
Las variantes son &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransitionHSL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransitionRGBAndMerge&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PaletteTransitionHSLAndMerge&amp;lt;/code&amp;gt;. Las dos variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; también tienen versión &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteTransitionRGB(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%PaletteTransitionHSLAndMerge(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%PaletteTransitionRGBAndMergeDefault(r1, r2, r3, targetpal, targetpalbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;targetpal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;targetpalbnk&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: calcular un paso intermedio de una transición&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; Este ejemplo trabaja con los primeros 15 colores de la copia de paletas.&lt;br /&gt;
    %SetRGBBaseDefault(#$0000, #$000F)&lt;br /&gt;
    %PaletteTransitionRGBAndMergeDefault(#$40, #$40, #$40, #!PaletteMyTargetRGB, #!PaletteMyTargetRGB&amp;gt;&amp;gt;16, #$0000, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo supone que &amp;lt;code&amp;gt;!PaletteMyTargetRGB&amp;lt;/code&amp;gt; corresponde a una paleta de destino RGB generada al instalar un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; de transición. Su dirección queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_target&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyTarget&amp;lt;/code&amp;gt;. Para HSL se utiliza la paleta convertida a HSL y la macro correspondiente.&lt;br /&gt;
&lt;br /&gt;
==== Aplicar un efecto de un archivo: DoEffect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DoEffect()&amp;lt;/code&amp;gt; aplica un efecto de un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%DoEffect(effect, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%DoEffectAndMerge(effect, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%DoEffectAndMergeDefaultRGB(effect, offset, length)&lt;br /&gt;
%DoEffectAndMergeDefaultHSL(effect, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;effect&amp;lt;/code&amp;gt;: ID del efecto, como &amp;lt;code&amp;gt;#!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt;.&lt;br /&gt;
* El origen debe contener colores RGB o HSL separados, según el efecto elegido.&lt;br /&gt;
* &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; guarda el resultado con 3 bytes por color para poder seguir modificándolo.&lt;br /&gt;
* &amp;lt;code&amp;gt;DoEffectAndMerge&amp;lt;/code&amp;gt; guarda colores en formato de SNES. Las variantes &amp;lt;code&amp;gt;DefaultRGB&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DefaultHSL&amp;lt;/code&amp;gt; eligen la base correspondiente y escriben en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: aplicar un efecto RGB a la paleta 8&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
    %DoEffectAndMergeDefaultRGB(#!PaletteEffectIDMyEffect0, #$81, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; se genera desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. El número final identifica el efecto dentro del archivo. Si el efecto trabaja en HSL, prepara la base HSL y utiliza &amp;lt;code&amp;gt;%DoEffectAndMergeDefaultHSL()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Convertir entre RGB y HSL ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%RGBToHSL()&amp;lt;/code&amp;gt; convierte colores RGB a HSL y &amp;lt;code&amp;gt;%HSLToRGB()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%RGBToHSL(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%HSLToRGB(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: convertir la base RGB a HSL&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %RGBToHSL(#DX_PPU_CGRAM_BaseRGBPalette, #DX_PPU_CGRAM_BaseRGBPalette&amp;gt;&amp;gt;16, #DX_PPU_CGRAM_BaseHSLPalette, #DX_PPU_CGRAM_BaseHSLPalette&amp;gt;&amp;gt;16, #$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Combinar un efecto propio con el global ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Suelen utilizarse después de &amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%ConcatenateRGBPaletteEffectToGlobal(sprite, paletteOption, palette)&lt;br /&gt;
%ConcatenateHSLPaletteEffectToGlobal(sprite, paletteOption, palette)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 recupera el índice del sprite desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 0 permite utilizar variables propias.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor de las opciones de paleta; activa el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; para incluir el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable que contiene la paleta asignada, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos.&lt;br /&gt;
* A de 16 bits: ID del efecto local RGB o HSL, según la macro.&lt;br /&gt;
* X de 8 bits: copia del valor de la paleta asignada.&lt;br /&gt;
* Y de 8 bits: conserva el valor devuelto por la asignación sin carga.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de los colores originales preparada por esa asignación.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: completar una asignación sin carga&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
; Llamar esta rutina con JSL después de asignar la paleta sin carga.&lt;br /&gt;
; Deben conservarse Y y $02-$04 de aquella llamada.&lt;br /&gt;
ApplyLocalEffect:&lt;br /&gt;
    LDA !NormalPalette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyEffect0&lt;br /&gt;
    %ConcatenateRGBPaletteEffectToGlobal(1, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; se genera desde un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. Para un efecto HSL, utiliza la macro HSL. Si usas Y para leer una tabla de efectos, guarda su valor con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; y recupéralo con &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; antes de concatenar.&lt;br /&gt;
&lt;br /&gt;
==== Elegir las direcciones y combinar varios efectos ====&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; 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:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;src&amp;lt;/code&amp;gt;: dónde leer los colores originales; &amp;lt;code&amp;gt;srcbnk&amp;lt;/code&amp;gt;: su banco.&lt;br /&gt;
* &amp;lt;code&amp;gt;dst&amp;lt;/code&amp;gt;: dónde guardar el resultado; &amp;lt;code&amp;gt;dstbnk&amp;lt;/code&amp;gt;: su banco. El destino debe ser un espacio de RAM que tu código pueda utilizar.&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: primer color que se procesará, contando desde 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt;: cantidad de colores que se procesarán.&lt;br /&gt;
&lt;br /&gt;
Para indicar una dirección fija, se utiliza &amp;lt;code&amp;gt;#Nombre&amp;lt;/code&amp;gt; para la dirección y &amp;lt;code&amp;gt;#Nombre&amp;gt;&amp;gt;16&amp;lt;/code&amp;gt; para su banco, como en el ejemplo de conversión RGB a HSL. También puedes pasar variables que contengan esos datos.&lt;br /&gt;
&lt;br /&gt;
El espacio necesario depende del paso que estés realizando:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Operación !! Lee !! Guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SetRGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SetHSLBase&amp;lt;/code&amp;gt; || Paleta normal: 2 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransition&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; sin &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| Variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Paleta normal: 2 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RGBToHSL&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;HSLToRGB&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si quieres aplicar dos efectos seguidos, el primero debe guardar sus colores separados, sin &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt;. El segundo lee ese resultado y utiliza &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; para dejar la paleta lista para cargarla. Si uno trabaja en RGB y el otro en HSL, convierte los colores entre ambos pasos.&lt;br /&gt;
&lt;br /&gt;
Las macros utilizan memoria temporal, entre otras las direcciones &amp;lt;code&amp;gt;$45-$50&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$51-$53&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8C&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8E&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$D5-$D7&amp;lt;/code&amp;gt;, según la operación. No guardes en ellas datos que necesites conservar después de la llamada.&lt;br /&gt;
&lt;br /&gt;
=== PPU ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué llamada elegir&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Necesitas… !! VRAM !! CGRAM&lt;br /&gt;
|-&lt;br /&gt;
| Indicar la dirección de origen y su banco por separado. || &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Indicar una dirección completa y dejar que la macro obtenga el banco. || &amp;lt;code&amp;gt;TransferToVRAMFromAddr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferToCGRAMFromAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Cargar un recurso completo registrado en Dynamic Xtreme. || &amp;lt;code&amp;gt;TransferResourceToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferResourceToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Cargar solo una cantidad de bytes de un recurso. || &amp;lt;code&amp;gt;TransferResourceToVRAMWithLenght&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferResourceToCGRAMWithLenght&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las versiones normales comprueban si la transferencia cabe dentro del límite de bytes del frame:&lt;br /&gt;
&lt;br /&gt;
* Carry activado: la transferencia quedó programada.&lt;br /&gt;
* Carry desactivado: no se programó porque superaría ese límite. Tu código puede intentarlo en otro frame.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== TransferToVRAM ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; programa una copia de gráficos desde ROM o RAM hacia VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToVRAM(VRAMOffset, ResourceAddr, ResourceBNK, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;VRAMOffset&amp;lt;/code&amp;gt;: dirección de destino en VRAM, expresada en palabras de 2 bytes. Por ejemplo, copiar &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes desde &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; ocupa las palabras &amp;lt;code&amp;gt;$6000-$60FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;ResourceAddr&amp;lt;/code&amp;gt;: dirección de origen dentro de su banco.&lt;br /&gt;
* &amp;lt;code&amp;gt;ResourceBNK&amp;lt;/code&amp;gt;: banco del origen.&lt;br /&gt;
* &amp;lt;code&amp;gt;Lenght&amp;lt;/code&amp;gt;: cantidad de bytes que se copiarán. Se conserva esta escritura del nombre porque así aparece en la macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: programar la carga de gráficos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToVRAM(#$6000, #!ResourceMyGraphics, #!ResourceMyGraphics&amp;gt;&amp;gt;16, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
    ; La copia se realizará en el próximo NMI.&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; es la dirección de un recurso registrado desde un DynamicInfo; queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;. La cantidad de bytes solicitada debe existir en ese recurso.&lt;br /&gt;
&lt;br /&gt;
==== TransferToVRAMFromAddr ====&lt;br /&gt;
&lt;br /&gt;
Hace la misma copia, pero recibe la dirección completa del origen. La macro separa su dirección y banco por ti.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToVRAMFromAddr(VRAMOffset, addr, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; se escribe sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;; los otros parámetros se entregan como en &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferToVRAMFromAddr(#$6000, !ResourceMyGraphics, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; se genera desde un recurso del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferResourceToVRAM y TransferResourceToVRAMWithLenght ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferResourceToVRAM(VRAMOffset, ResourceName)&lt;br /&gt;
%TransferResourceToVRAMWithLenght(VRAMOffset, ResourceName, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para un recurso cuyos defines sean &amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceMyGraphicsSize&amp;lt;/code&amp;gt;, escribe &amp;lt;code&amp;gt;&amp;quot;MyGraphics&amp;quot;&amp;lt;/code&amp;gt; como &amp;lt;code&amp;gt;ResourceName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: cargar el recurso completo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToVRAM(#$6000, &amp;quot;MyGraphics&amp;quot;)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: cargar solo sus primeros $0200 bytes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToVRAMWithLenght(#$6000, &amp;quot;MyGraphics&amp;quot;, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El nombre y el tamaño se obtienen de los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; al instalar los recursos del DynamicInfo. Utiliza el nombre normalizado: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;, eliminando los separadores y poniendo en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
==== TransferToCGRAM ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt; programa una copia de colores desde ROM o RAM hacia una paleta de SNES.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToCGRAM(CGRAMOffset, TableAddr, TableBNK, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;: número del primer color de destino, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Por ejemplo, la paleta 8 comienza en el color &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;TableAddr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TableBNK&amp;lt;/code&amp;gt;: dirección y banco de los colores que se van a copiar.&lt;br /&gt;
* &amp;lt;code&amp;gt;Lenght&amp;lt;/code&amp;gt;: cantidad de bytes. Cada color ocupa 2 bytes; 15 colores ocupan &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar los 15 colores visibles de la paleta 8&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToCGRAM(#$81, #DX_PPU_CGRAM_PaletteWriteMirror+$0102, #DX_PPU_CGRAM_PaletteWriteMirror&amp;gt;&amp;gt;16, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Este ejemplo toma el resultado de un efecto guardado en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;. El desplazamiento &amp;lt;code&amp;gt;$0102&amp;lt;/code&amp;gt; corresponde al color &amp;lt;code&amp;gt;$81&amp;lt;/code&amp;gt;, porque cada color ocupa 2 bytes. Se omite el primer color de la paleta, que es transparente en sprites.&lt;br /&gt;
&lt;br /&gt;
==== TransferToCGRAMFromAddr ====&lt;br /&gt;
&lt;br /&gt;
Hace la misma copia de colores, pero recibe la dirección completa del origen. Escribe &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToCGRAMFromAddr(CGRAMOffset, addr, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToCGRAMFromAddr(#$81, DX_PPU_CGRAM_PaletteWriteMirror+$0102, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== TransferResourceToCGRAM y TransferResourceToCGRAMWithLenght ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferResourceToCGRAM(CGRAMOffset, ResourceName)&lt;br /&gt;
%TransferResourceToCGRAMWithLenght(CGRAMOffset, ResourceName, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar un recurso completo de colores&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToCGRAM(#$80, &amp;quot;MyColors&amp;quot;)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar solo 15 colores&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToCGRAMWithLenght(#$81, &amp;quot;MyColors&amp;quot;, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Estos ejemplos suponen un recurso general de colores con los defines &amp;lt;code&amp;gt;!ResourceMyColors&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceMyColorsSize&amp;lt;/code&amp;gt;, generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; desde un DynamicInfo. Utiliza el nombre normalizado: &amp;lt;code&amp;gt;my_colors&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyColors&amp;lt;/code&amp;gt;. En el segundo ejemplo, el recurso debe comenzar con los 15 colores que se quieren copiar, sin anteponer el color transparente.&lt;br /&gt;
&lt;br /&gt;
==== Variantes Forced ====&lt;br /&gt;
&lt;br /&gt;
Todas las transferencias anteriores tienen una variante cuyo nombre comienza con &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;. Programa la copia aunque supere el límite de bytes del frame. La cantidad copiada también se suma al total de ese frame.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! VRAM !! CGRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferToVRAMFromAddr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferToCGRAMFromAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferResourceToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferResourceToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferResourceToVRAMWithLenght&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferResourceToCGRAMWithLenght&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Reciben los mismos parámetros que las versiones sin &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %ForcedTransferResourceToVRAM(#$6000, &amp;quot;MyGraphics&amp;quot;)&lt;br /&gt;
    ; No se comprueba el carry en esta variante.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt; corresponde al recurso &amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, generado desde el DynamicInfo. Se utiliza el nombre normalizado, como &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Matemáticas ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Prepara A en modo de 8 bits antes de llamarlas. Las macros no cambian por ti el tamaño de A, X o Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cómo escribir los argumentos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Mul&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Div&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MulAfterMul&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DivAfterDiv&amp;lt;/code&amp;gt; pegan el argumento directamente después de &amp;lt;code&amp;gt;LDA&amp;lt;/code&amp;gt;. Escribe el argumento entre comillas con un espacio al principio: &amp;lt;code&amp;gt;&amp;quot; #$05&amp;quot;&amp;lt;/code&amp;gt; produce &amp;lt;code&amp;gt;LDA #$05&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También puedes comenzar el argumento con &amp;lt;code&amp;gt;.b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;.l&amp;lt;/code&amp;gt; para elegir cómo se escribe el acceso a memoria. Por ejemplo, si &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; contiene el número que quieres multiplicar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot;.b $02&amp;quot;, &amp;quot; #$07&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esto genera &amp;lt;code&amp;gt;LDA.b $02&amp;lt;/code&amp;gt; para leer el primer número y &amp;lt;code&amp;gt;LDA #$07&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Las variantes con &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt;, además de &amp;lt;code&amp;gt;MulAfterDiv&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DivAfterMul&amp;lt;/code&amp;gt;, ya añaden un espacio antes de los argumentos. En ellas puedes escribir los valores normalmente, como &amp;lt;code&amp;gt;%MulW(#$05, #$07)&amp;lt;/code&amp;gt;. En la implementación actual no se pasan los sufijos &amp;lt;code&amp;gt;.b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;.l&amp;lt;/code&amp;gt; de esta misma manera a esas variantes, porque el espacio que añaden quedaría entre &amp;lt;code&amp;gt;LDA&amp;lt;/code&amp;gt; y el sufijo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;¿Qué significa la W?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El hardware necesita un pequeño tiempo para terminar el cálculo. Las macros con &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; incluyen esa espera: puedes leer el resultado inmediatamente después. Las versiones sin &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los resultados se leen mediante estos defines:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!MultiplicationResult&amp;lt;/code&amp;gt;: resultado de multiplicar, de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;!DivisionResult&amp;lt;/code&amp;gt;: cociente de la división, de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;!RemainderResult&amp;lt;/code&amp;gt;: resto de la división, de 16 bits.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Mul y MulW ====&lt;br /&gt;
&lt;br /&gt;
Multiplican dos valores de 8 bits y producen un resultado de 16 bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Mul(a, b)&lt;br /&gt;
%MulW(a, b)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; pueden ser valores inmediatos, como &amp;lt;code&amp;gt;#$06&amp;lt;/code&amp;gt;, o variables de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: 6 × 7 = 42&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %MulW(#$06, #$07)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $002A, es decir, 42&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La llamada sin espera sería &amp;lt;code&amp;gt;%Mul(&amp;quot; #$06&amp;quot;, &amp;quot; #$07&amp;quot;)&amp;lt;/code&amp;gt;. En ese caso no leas el resultado inmediatamente: ejecuta antes otro código que no utilice el hardware de multiplicación o división.&lt;br /&gt;
&lt;br /&gt;
==== Div y DivW ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Div(ah, al, b)&lt;br /&gt;
%DivW(ah, al, b)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;ah&amp;lt;/code&amp;gt;: byte alto del número que quieres dividir.&lt;br /&gt;
* &amp;lt;code&amp;gt;al&amp;lt;/code&amp;gt;: byte bajo del mismo número.&lt;br /&gt;
* &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;: número por el que divides, entre 1 y 255.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: 300 ÷ 7 = 42, con resto 6&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; 300 = $012C: byte alto $01, byte bajo $2C.&lt;br /&gt;
    %DivW(#$01, #$2C, #$07)&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $002A, es decir, 42&lt;br /&gt;
    LDA !RemainderResult         ; A = $0006&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
También puedes pasar una variable de 16 bits como dos argumentos: &amp;lt;code&amp;gt;%DivW(MiNumero+1, MiNumero, #$07)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;MiNumero&amp;lt;/code&amp;gt; representa aquí una variable definida por tu código.&lt;br /&gt;
&lt;br /&gt;
==== Continuar desde el resultado anterior ====&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;AfterMul&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;AfterDiv&amp;lt;/code&amp;gt; toman el resultado del cálculo anterior como primer número. Solo debes indicar el segundo número.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Macro !! Cálculo que realiza&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MulAfterMul(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MulWAfterMul(b)&amp;lt;/code&amp;gt; || Toma los 8 bits bajos del resultado de la multiplicación anterior y los multiplica por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MulAfterDiv(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MulWAfterDiv(b)&amp;lt;/code&amp;gt; || Toma los 8 bits bajos del cociente anterior y los multiplica por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DivAfterMul(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DivWAfterMul(b)&amp;lt;/code&amp;gt; || Divide el resultado completo de la multiplicación anterior por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DivAfterDiv(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DivWAfterDiv(b)&amp;lt;/code&amp;gt; || Divide el cociente completo de la división anterior por b.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La W sigue indicando que puedes leer el nuevo resultado inmediatamente después. Las variantes &amp;lt;code&amp;gt;After...&amp;lt;/code&amp;gt; ya incluyen la espera que necesitan para tomar el resultado del cálculo anterior.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dos multiplicaciones, (6 × 7) × 2 = 84&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot; #$06&amp;quot;, &amp;quot; #$07&amp;quot;)&lt;br /&gt;
    %MulWAfterMul(#$02)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $0054, es decir, 84&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dividir y después multiplicar, (100 ÷ 4) × 3 = 75&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Div(&amp;quot; #$00&amp;quot;, &amp;quot; #$64&amp;quot;, &amp;quot; #$04&amp;quot;)&lt;br /&gt;
    %MulWAfterDiv(#$03)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $004B, es decir, 75&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: multiplicar y después dividir, (20 × 15) ÷ 4 = 75&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot; #$14&amp;quot;, &amp;quot; #$0F&amp;quot;)&lt;br /&gt;
    %DivWAfterMul(#$04)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $004B, es decir, 75&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dos divisiones, (300 ÷ 3) ÷ 4 = 25&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Div(&amp;quot; #$01&amp;quot;, &amp;quot; #$2C&amp;quot;, &amp;quot; #$03&amp;quot;)&lt;br /&gt;
    %DivWAfterDiv(#$04)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $0019, es decir, 25&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En las multiplicaciones, el primer número siempre se limita a 8 bits. Si el resultado anterior era mayor que 255, &amp;lt;code&amp;gt;MulAfterMul&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;MulAfterDiv&amp;lt;/code&amp;gt; solo utilizará su byte bajo. Las divisiones de esta tabla sí toman el resultado anterior completo, de 16 bits.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_sprite_creation_guide&amp;diff=21351</id>
		<title>es/Dynamic Xtreme sprite creation guide</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_sprite_creation_guide&amp;diff=21351"/>
		<updated>2026-10-24T04:45:36Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_sprite_creation_guide}}&lt;br /&gt;
&lt;br /&gt;
En este artículo se explicará cómo crear sprites dinámicos utilizando Dynamic Xtreme y PIXI.&lt;br /&gt;
&lt;br /&gt;
La guía recorrerá el proceso completo: preparar los gráficos, definir las poses, incluir los archivos necesarios en el sprite y utilizar el sistema para cargar y dibujar sus poses en pantalla.&lt;br /&gt;
&lt;br /&gt;
== Requisitos ==&lt;br /&gt;
&lt;br /&gt;
Para seguir esta guía necesitas:&lt;br /&gt;
&lt;br /&gt;
* Tener [https://www.smwcentral.net/?p=section&amp;amp;s=tools&amp;amp;f%5Bname%5D=PIXI PIXI] instalado y configurado para insertar sprites en tu ROM.&lt;br /&gt;
* Tener Dynamic Xtreme instalado y configurado. Si todavía no lo has hecho, consulta la [[Dynamic_Xtreme_Quick_Start|guía de inicio rápido]].&lt;br /&gt;
&lt;br /&gt;
== Archivos utilizados por un sprite dinámico ==&lt;br /&gt;
&lt;br /&gt;
Además de los archivos utilizados normalmente por PIXI, un sprite dinámico necesita los siguientes archivos:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Archivo gráfico (*.bin):&#039;&#039;&#039; contiene los gráficos de las poses del sprite.&lt;br /&gt;
* &#039;&#039;&#039;DynamicInfo (*.dynamicinfo):&#039;&#039;&#039; indica qué gráficos utiliza el sprite y cómo se dividen en poses.&lt;br /&gt;
* &#039;&#039;&#039;DrawInfo (*.drawinfo):&#039;&#039;&#039; contiene la información necesaria para dibujar las poses.&lt;br /&gt;
* &#039;&#039;&#039;Archivo ASM (*.asm):&#039;&#039;&#039; contiene el código del sprite y utiliza los recursos anteriores.&lt;br /&gt;
&lt;br /&gt;
Una posible estructura consiste en guardar los archivos de Dynamic Xtreme junto al propio recurso de PIXI. Por ejemplo, un sprite normal podría organizarse de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PIXI/&lt;br /&gt;
└── sprites/&lt;br /&gt;
    └── MySprite/&lt;br /&gt;
        ├── MySprite.asm&lt;br /&gt;
        ├── MySprite.json&lt;br /&gt;
        └── DynamicXtreme/&lt;br /&gt;
            ├── MySprite.bin&lt;br /&gt;
            ├── MySprite.dynamicinfo&lt;br /&gt;
            └── MySprite.drawinfo&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El archivo ASM y el archivo de configuración permanecen en la carpeta principal del sprite. Los gráficos, el DynamicInfo y el DrawInfo se guardan dentro de la subcarpeta &amp;lt;code&amp;gt;DynamicXtreme&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
En este caso, el ASM principal del sprite debe incluir el DynamicInfo y el DrawInfo mediante las siguientes directivas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;#incdyn &amp;quot;DynamicXtreme/MySprite.dynamicinfo&amp;quot;&lt;br /&gt;
;#incdri &amp;quot;DynamicXtreme/MySprite.drawinfo&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las rutas son relativas al archivo ASM que contiene las directivas. Si se trabaja con un cluster sprite, extended sprite u otro tipo admitido por PIXI, la carpeta completa del recurso puede organizarse de la misma manera dentro de la carpeta correspondiente de PIXI.&lt;br /&gt;
&lt;br /&gt;
También es posible utilizar las carpetas tradicionales de Dynamic Xtreme. En ese caso, el archivo &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt; se coloca en &amp;lt;code&amp;gt;DynamicInfos&amp;lt;/code&amp;gt;, el archivo &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DrawInfos&amp;lt;/code&amp;gt; y los gráficos &amp;lt;code&amp;gt;*.bin&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;DynamicResources&amp;lt;/code&amp;gt;. Los archivos guardados de esta forma son encontrados directamente por Dynamic Xtreme y no necesitan las directivas &amp;lt;code&amp;gt;;#incdyn&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;;#incdri&amp;lt;/code&amp;gt; en el sprite.&lt;br /&gt;
&lt;br /&gt;
La primera opción facilita distribuir el sprite con todos sus recursos dentro de una sola carpeta, mientras que la segunda mantiene la organización tradicional de Dynamic Xtreme. Para conocer la estructura y las reglas de cada formato, consulta [[Dynamic_Xtreme_files_and_formats|Archivos y formatos de Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
== Estructura del sprite ==&lt;br /&gt;
&lt;br /&gt;
Un sprite dinámico conserva la estructura habitual de un sprite de PIXI, pero debe preparar las variables utilizadas por Dynamic Xtreme y organizar su rutina principal según se encuentre dentro o fuera de su área de renderizado.&lt;br /&gt;
&lt;br /&gt;
La estructura que se utilizará en esta guía se divide en las siguientes partes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;INIT:&#039;&#039;&#039; inicializa las variables del sprite y el estado utilizado por Dynamic Xtreme.&lt;br /&gt;
* &#039;&#039;&#039;Short routine:&#039;&#039;&#039; ejecuta la lógica que debe continuar incluso cuando el sprite se encuentra fuera del área de renderizado.&lt;br /&gt;
* &#039;&#039;&#039;Long routine:&#039;&#039;&#039; maneja las tareas que solamente son necesarias dentro del área de renderizado, como solicitar la pose y dibujarla.&lt;br /&gt;
&lt;br /&gt;
=== Incluir los defines del tipo de sprite ===&lt;br /&gt;
&lt;br /&gt;
Antes del código del sprite se debe incluir el archivo de defines correspondiente al tipo de recurso utilizado:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt; para sprites normales.&lt;br /&gt;
* &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; para cluster sprites.&lt;br /&gt;
* &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; para extended sprites.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si el ASM de un sprite normal se encuentra dentro de una subcarpeta de &amp;lt;code&amp;gt;sprites&amp;lt;/code&amp;gt;, el include puede escribirse de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
incsrc &amp;quot;../NormalSpriteDefines.asm&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La ruta siempre es relativa a la ubicación del archivo ASM del sprite, por lo que debe ajustarse a la estructura de carpetas utilizada por el recurso. Este archivo proporciona los aliases de tablas y rutinas correspondientes a su tipo de sprite; gracias a esto, nombres como &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; apuntan a la implementación correcta para un sprite normal, cluster o extended.&lt;br /&gt;
&lt;br /&gt;
=== INIT ===&lt;br /&gt;
&lt;br /&gt;
En los sprites normales, la rutina &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; debe establecer las distancias utilizadas por el &amp;lt;code&amp;gt;RenderBox&amp;lt;/code&amp;gt;, asignar los valores iniciales del sprite e invalidar cualquier estado anterior que pueda permanecer en el mismo slot de PIXI.&lt;br /&gt;
&lt;br /&gt;
El siguiente ejemplo corresponde a un sprite normal. Inicia el sprite con la pose 0 y obtiene la versión y el volteo inicial desde la configuración de PIXI:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
print &amp;quot;INIT &amp;quot;,pc&lt;br /&gt;
    LDA.b #!RenderBoxXDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderXDistanceOutOfScreen,x&lt;br /&gt;
    LDA.b #!RenderBoxYDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderYDistanceOutOfScreen,x&lt;br /&gt;
&lt;br /&gt;
    LDA !ExtraBits,x&lt;br /&gt;
    AND #$04&lt;br /&gt;
    LSR&lt;br /&gt;
    LSR&lt;br /&gt;
    STA !GlobalFlip,x&lt;br /&gt;
&lt;br /&gt;
    LDA !ExtraByte1,x&lt;br /&gt;
    AND #$0F&lt;br /&gt;
    STA !Version,x&lt;br /&gt;
&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    STA !PoseIndex,x&lt;br /&gt;
    STA !LocalFlip,x&lt;br /&gt;
    STA !LastFlip,x&lt;br /&gt;
&lt;br /&gt;
    LDA #$FF&lt;br /&gt;
    STA !Palette,x&lt;br /&gt;
    STA !LastPoseIndex,x&lt;br /&gt;
    STA !LastPoseHashIndex,x&lt;br /&gt;
    STA !LastVersion,x&lt;br /&gt;
&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cada variable del ejemplo cumple una función concreta:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen&amp;lt;/code&amp;gt; guardan las distancias que utilizará &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; para decidir si el sprite todavía se encuentra lo bastante cerca de la pantalla como para renderizarse. Los valores &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; son generados a partir del DrawInfo y quedan disponibles en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre del recurso se normaliza para formar el define: se eliminan separadores como espacios y guiones bajos, y la inicial de cada palabra se escribe en mayúscula. Por ejemplo, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;my sprite&amp;lt;/code&amp;gt; se convierten en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; indica la pose dinámica que el sprite desea utilizar dentro del DynamicInfo. El valor 0 selecciona la primera pose del recurso. Una rutina de animación puede asignar otro valor antes de solicitar los gráficos.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt; identifica la variante actual del sprite. Una versión puede cambiar su paleta, sus gráficos o incluso su comportamiento. En los sprites normales es habitual tomarla de los cuatro bits bajos de &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt;, lo que permite seleccionar hasta 16 versiones distintas desde Lunar Magic.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip&amp;lt;/code&amp;gt; representa el volteo general del sprite. En los sprites normales puede obtenerse del extra bit: 0 mantiene la orientación original y 1 aplica el volteo inicial. &amp;lt;code&amp;gt;!LocalFlip&amp;lt;/code&amp;gt; permite aplicar un volteo adicional a la pose actual. Dynamic Xtreme combina ambos valores y conserva en &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt; el volteo efectivo utilizado para dibujar.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt; guarda la paleta asignada actualmente. Se inicia en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; porque el sprite todavía no posee una paleta válida.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; guarda la última pose que Dynamic Xtreme pudo obtener correctamente, y &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; guarda el slot de la caché de VRAM donde se encuentra. Ambos comienzan en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; porque todavía no existe una pose disponible.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt; guarda la versión procesada anteriormente por el manejo de paletas. Iniciarla en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; hace que la primera versión del sprite sea procesada aunque &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt; comience en 0.&lt;br /&gt;
&lt;br /&gt;
Si un sprite utiliza varios DrawInfo, las distancias deben cubrir el conjunto completo de sus gráficos. Se recomienda revisar en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; los valores generados para cada DrawInfo y utilizar la mayor distancia horizontal y la mayor distancia vertical. Por ejemplo, si la cabeza y el cuerpo utilizan DrawInfo diferentes, tomar solamente las distancias de la cabeza podría hacer que el sprite deje de dibujarse cuando una parte de su cuerpo todavía se encuentra dentro de la pantalla.&lt;br /&gt;
&lt;br /&gt;
Los valores marcados con &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; representan estados inválidos. Además de indicar que el sprite todavía no tiene una paleta o pose disponible, evitan reutilizar información dejada por otro sprite que haya ocupado anteriormente el mismo slot de PIXI.&lt;br /&gt;
&lt;br /&gt;
==== Inicialización de cluster y extended sprites ====&lt;br /&gt;
&lt;br /&gt;
Los cluster sprites y extended sprites no tienen una rutina &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; propia. Para inicializarlos una sola vez se reserva una de sus tablas, por ejemplo &amp;lt;code&amp;gt;!ClusterMiscTable1&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!ExtendedMiscTable1&amp;lt;/code&amp;gt;, y se le asigna un nombre como &amp;lt;code&amp;gt;!Started&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!Started = !ClusterMiscTable1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cuando se crea el sprite, &amp;lt;code&amp;gt;!Started&amp;lt;/code&amp;gt; debe establecerse en 0 utilizando el índice del nuevo cluster o extended sprite. Esto es necesario porque el slot pudo haber sido utilizado anteriormente y todavía podría contener el valor de otro sprite.&lt;br /&gt;
&lt;br /&gt;
Al comienzo de &amp;lt;code&amp;gt;SpriteCode&amp;lt;/code&amp;gt;, antes de ejecutar &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;, se comprueba esta variable:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpriteCode:&lt;br /&gt;
    LDA !Started,x&lt;br /&gt;
    BNE +&lt;br /&gt;
    JSR Start&lt;br /&gt;
    RTS&lt;br /&gt;
+&lt;br /&gt;
    !RenderBox&lt;br /&gt;
    ; Resto del código del sprite&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La rutina &amp;lt;code&amp;gt;Start&amp;lt;/code&amp;gt; contiene la inicialización que un sprite normal realizaría en &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt;. Al finalizar, establece &amp;lt;code&amp;gt;!Started&amp;lt;/code&amp;gt; en 1 para que no vuelva a ejecutarse durante los frames siguientes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Start:&lt;br /&gt;
    ; Aquí va la inicialización del sprite&lt;br /&gt;
&lt;br /&gt;
    LDA #$01&lt;br /&gt;
    STA !Started,x&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Como &amp;lt;code&amp;gt;Start&amp;lt;/code&amp;gt; se llama mediante &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;, debe terminar con &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;. El código que crea el cluster o extended sprite también debe preparar cualquier dato que deba heredarse del sprite principal, como &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!GlobalFlip&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== PaletteOption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; controla la paleta solicitada y si esta será afectada por el efecto global de paleta. Su formato es el siguiente:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EPPP----&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; indica si la paleta será afectada por el efecto global: 0 la excluye y 1 lo habilita.&lt;br /&gt;
* &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; representa una paleta entre 8 y F: &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; corresponde a la paleta 8 y &amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt; a la paleta F.&lt;br /&gt;
* Los cuatro bits bajos no forman parte de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cuando se utiliza asignación automática, &amp;lt;code&amp;gt;PPP = 000&amp;lt;/code&amp;gt; permite buscar un slot libre entre las ocho paletas, un valor &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; limita la búsqueda a las paletas 8-B y un valor &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; la limita a las paletas C-F. Con asignación manual, &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; selecciona directamente la paleta que se utilizará.&lt;br /&gt;
&lt;br /&gt;
En los sprites normales, &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; utiliza directamente &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt;. Lo habitual es aprovechar los cuatro bits restantes para seleccionar la versión del sprite, por lo que el byte completo utiliza el siguiente formato:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EPPPVVVV&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;EPPP&amp;lt;/code&amp;gt; contiene las opciones de paleta descritas anteriormente.&lt;br /&gt;
* &amp;lt;code&amp;gt;VVVV&amp;lt;/code&amp;gt; selecciona una de las 16 versiones posibles del sprite, desde 0 hasta 15.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; utiliza los cuatro bits altos directamente, mientras que el &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; copia los cuatro bits bajos a &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt;. No es necesario copiar &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; a otra tabla.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignmentOption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; determina cómo se asignará la paleta al sprite:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--AA----&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 00&amp;lt;/code&amp;gt;: &#039;&#039;&#039;asignación automática&#039;&#039;&#039;. Dynamic Xtreme busca un slot permitido por &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; y carga la paleta dinámicamente.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 01&amp;lt;/code&amp;gt;: &#039;&#039;&#039;asignación manual&#039;&#039;&#039;. &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; indica el slot exacto y Dynamic Xtreme carga la paleta dinámicamente.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 10&amp;lt;/code&amp;gt;: &#039;&#039;&#039;asignación manual sin carga&#039;&#039;&#039;. El sprite utiliza directamente la paleta que ya existe en el nivel y Dynamic Xtreme no carga una nueva.&lt;br /&gt;
&lt;br /&gt;
En los sprites normales, &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; utiliza directamente &amp;lt;code&amp;gt;!ExtraProp2,x&amp;lt;/code&amp;gt;. Por lo tanto, el modo se configura mediante los bits 5 y 4 del Extra Property Byte 2 y tampoco necesita copiarse a otra tabla durante el &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
En los cluster sprites y extended sprites, &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; deben establecerse manualmente cuando son creados. Normalmente se copia el modo de asignación del sprite que los genera. Al copiar &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt;, sus cuatro bits bajos deben borrarse porque en un sprite normal contienen la versión y no forman parte de la opción de paleta.&lt;br /&gt;
&lt;br /&gt;
Si el sprite generado utiliza la misma paleta que el sprite principal, puede copiar su &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; después de borrar los cuatro bits bajos. Si utiliza una paleta distinta y el sprite principal emplea asignación automática, puede conservarse el mismo rango de búsqueda. Si el sprite principal emplea asignación manual o asignación manual sin carga, se suma &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; al valor enmascarado para seleccionar la paleta siguiente.&lt;br /&gt;
&lt;br /&gt;
Además de estas variables, el &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; puede inicializar cualquier tabla propia que necesite el comportamiento del sprite.&lt;br /&gt;
&lt;br /&gt;
=== SpriteCode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SpriteCode&amp;lt;/code&amp;gt; comienza ejecutando &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;. Esta rutina devuelve el carry activado cuando el sprite se encuentra dentro de su área de renderizado y desactivado cuando está fuera de ella. Con este resultado se decide si ejecutar la short routine o la long routine.&lt;br /&gt;
&lt;br /&gt;
Una estructura base puede escribirse de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpriteCode:&lt;br /&gt;
    !RenderBox&lt;br /&gt;
    BCS .LongRoutine&lt;br /&gt;
&lt;br /&gt;
.ShortRoutine&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    %SubOffScreen()&lt;br /&gt;
    ; Aquí va la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&lt;br /&gt;
.LongRoutine&lt;br /&gt;
    JSR PaletteManagement&lt;br /&gt;
    BCC ..Return&lt;br /&gt;
&lt;br /&gt;
    JSR PoseManagement&lt;br /&gt;
    BCC ..Return&lt;br /&gt;
&lt;br /&gt;
    JSR Draw&lt;br /&gt;
    ; Aquí va la lógica de tu sprite&lt;br /&gt;
..Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Short routine ====&lt;br /&gt;
&lt;br /&gt;
La short routine se ejecuta cuando el sprite se encuentra fuera del área calculada por &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;. Aquí solamente debe ejecutarse la lógica base necesaria para mantener el comportamiento del sprite, sin solicitar gráficos dinámicos, procesar su paleta ni dibujarlo. El contenido exacto depende del sprite y puede incluir su movimiento, estado, temporizadores, interacciones o animación.&lt;br /&gt;
&lt;br /&gt;
En los sprites normales se recomienda llamar a &amp;lt;code&amp;gt;%SubOffScreen()&amp;lt;/code&amp;gt; dentro de esta parte. 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. De esta manera PIXI puede eliminar el sprite cuando se aleja lo suficiente de la pantalla, sin ejecutar esta comprobación durante la parte más costosa del renderizado.&lt;br /&gt;
&lt;br /&gt;
==== Long routine ====&lt;br /&gt;
&lt;br /&gt;
La long routine se ejecuta cuando el sprite está dentro del área de renderizado. Esta ruta realiza el proceso completo: maneja la paleta, solicita la pose dinámica o actualiza su registro de uso si ya está en VRAM para evitar que sea sobrescrita, dibuja el sprite y finalmente ejecuta la misma lógica base de la short routine.&lt;br /&gt;
&lt;br /&gt;
No es necesario llamar nuevamente a &amp;lt;code&amp;gt;%SubOffScreen()&amp;lt;/code&amp;gt; dentro de la long routine. Como &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; ya determinó que el sprite se encuentra dentro del área de renderizado, realizar allí la comprobación resulta redundante.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;PaletteManagement&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PoseManagement&amp;lt;/code&amp;gt; devuelven el carry activado cuando existe un recurso utilizable. Si alguna de ellas devuelve el carry desactivado, el ejemplo salta a &amp;lt;code&amp;gt;.ShortRoutine&amp;lt;/code&amp;gt;: el sprite no se dibuja durante ese frame, pero su lógica continúa ejecutándose.&lt;br /&gt;
&lt;br /&gt;
Las rutinas de paleta, poses y dibujo se desarrollarán en los apartados siguientes. Los nombres utilizados aquí son solamente una forma de organizar el código y pueden cambiarse según la estructura del sprite.&lt;br /&gt;
&lt;br /&gt;
== Manejo de Paleta de Colores ==&lt;br /&gt;
&lt;br /&gt;
=== Cargar una paleta dinámica ===&lt;br /&gt;
&lt;br /&gt;
La carga de una paleta dinámica se realiza mediante &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;. Solamente se debe cargar en A, con 16 bits, el offset de la tabla de paletas generado para el recurso:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignment&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera a partir de las paletas declaradas en el DynamicInfo y queda disponible en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre del DynamicInfo se normaliza eliminando espacios, guiones bajos y otros separadores, y escribiendo en mayúscula la inicial de cada palabra. Por ejemplo, &amp;lt;code&amp;gt;my_sprite.dynamicinfo&amp;lt;/code&amp;gt; genera el componente &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt; para seleccionar una entrada de la tabla: la versión 0 utiliza la primera paleta, la versión 1 utiliza la segunda y así sucesivamente. También utiliza &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption&amp;lt;/code&amp;gt; para decidir dónde y cómo asignarla.&lt;br /&gt;
&lt;br /&gt;
La rutina devuelve el carry activado cuando existe una paleta utilizable y desactivado cuando todavía no fue posible obtenerla. Por esta razón, &amp;lt;code&amp;gt;SpriteCode&amp;lt;/code&amp;gt; comprueba el carry antes de continuar con la carga de poses y el dibujo. &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; debe ejecutarse en cada frame de la long routine para conservar la asignación mientras el sprite siga utilizándola.&lt;br /&gt;
&lt;br /&gt;
=== Seleccionar una paleta sin cambiar la versión del sprite ===&lt;br /&gt;
&lt;br /&gt;
La paleta de un sprite puede cambiar sin que su versión o su comportamiento tengan que cambiar. Por ejemplo, un sprite puede alternar entre su paleta normal y una segunda paleta durante una animación o un estado temporal. Mantener ambas paletas como recursos independientes también permite que la segunda sea reutilizada por otros sprites.&lt;br /&gt;
&lt;br /&gt;
Como &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; selecciona la entrada mediante &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt;, puede guardarse temporalmente la versión lógica del sprite, asignar el índice de la paleta deseada y restaurar después el valor original:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    LDA !Version,x&lt;br /&gt;
    PHA&lt;br /&gt;
&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !Version,x&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignment&lt;br /&gt;
&lt;br /&gt;
    PLA&lt;br /&gt;
    STA !Version,x&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; utiliza la entrada 2 de la tabla, pero el comportamiento del sprite conserva su versión original. De esta forma, la selección de la paleta queda separada de la variante lógica del personaje. &amp;lt;code&amp;gt;PLA&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;STA&amp;lt;/code&amp;gt; no alteran el carry, por lo que &amp;lt;code&amp;gt;PaletteManagement&amp;lt;/code&amp;gt; todavía devuelve correctamente el resultado de &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; utilizado aquí se genera desde el DynamicInfo y se encuentra en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa la misma normalización: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra, de modo que &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Concatenar un efecto local con el efecto global ===&lt;br /&gt;
&lt;br /&gt;
Cuando la paleta necesita un efecto propio que además debe combinarse con el efecto global de paleta, se utiliza &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; seguido de &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    PHY&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
&lt;br /&gt;
    LDA $14&lt;br /&gt;
    AND #$06&lt;br /&gt;
    TAY&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA PaletteEffects,y&lt;br /&gt;
&lt;br /&gt;
    PLY&lt;br /&gt;
    !ConcatenateRGBPaletteEffectToGlobal&lt;br /&gt;
&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&lt;br /&gt;
PaletteEffects:&lt;br /&gt;
    dw !PaletteEffectIDMyEffect0&lt;br /&gt;
    dw !PaletteEffectIDMyEffect1&lt;br /&gt;
    dw !PaletteEffectIDMyEffect2&lt;br /&gt;
    dw !PaletteEffectIDMyEffect3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; asigna la paleta y prepara su dirección base sin realizar todavía la carga final. También deja en Y la información que la rutina de concatenación necesita para decidir si debe reconstruir el efecto.&lt;br /&gt;
&lt;br /&gt;
En este ejemplo se utiliza &amp;lt;code&amp;gt;$14&amp;lt;/code&amp;gt;, el contador principal de frames de Super Mario World, para seleccionar uno de cuatro efectos. Como Y se necesita temporalmente para leer la tabla &amp;lt;code&amp;gt;PaletteEffects&amp;lt;/code&amp;gt;, primero se conserva con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; y se restaura con &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt;. El valor restaurado debe llegar sin modificaciones a la rutina de concatenación.&lt;br /&gt;
&lt;br /&gt;
Antes de concatenar, X debe contener el valor de &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, que ya representa el índice requerido por la rutina. A debe contener, con 16 bits, el ID del efecto local. En el ejemplo, Y se utiliza como índice para cargar ese ID desde una tabla, pero el ID finalmente se entrega en A.&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y se encuentra en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los defines &amp;lt;code&amp;gt;!PaletteEffectIDMyEffectX&amp;lt;/code&amp;gt; son generados a partir de un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; durante la instalación y se guardan en el mismo archivo. En ambos casos los nombres se normalizan eliminando espacios, guiones bajos y otros separadores, y escribiendo en mayúscula la inicial de cada palabra. Por ejemplo, &amp;lt;code&amp;gt;my_effect.paleffect&amp;lt;/code&amp;gt; genera el componente &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; corresponde al índice del efecto dentro de la colección.&lt;br /&gt;
&lt;br /&gt;
Se utiliza &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; para efectos que trabajan en RGB, como &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, y &amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt; para efectos que trabajan en HSL, como &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;. Para combinar el efecto local con el global, el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;PaletteOption&amp;lt;/code&amp;gt; debe estar activado. La rutina realiza internamente las conversiones necesarias cuando ambos efectos utilizan espacios de color diferentes. Para conocer el espacio de color de cada efecto, consulta [https://sneslab.net/wiki/es/Dynamic_Xtreme_files_and_formats#Tipos_de_efectos Tipos de efectos].&lt;br /&gt;
&lt;br /&gt;
La concatenación devuelve el carry activado cuando existe un resultado utilizable, incluido un resultado anterior usado como respaldo, y desactivado cuando esa paleta todavía no posee ningún resultado válido. Este carry debe conservarse para que &amp;lt;code&amp;gt;SpriteCode&amp;lt;/code&amp;gt; pueda decidir si continúa con el dibujo.&lt;br /&gt;
&lt;br /&gt;
== Manejo de Poses Dinámicas ==&lt;br /&gt;
&lt;br /&gt;
Las poses dinámicas se solicitan mediante &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;. Estas rutinas buscan la pose en la caché de VRAM y, si todavía no está disponible, solicitan su carga. Deben ejecutarse en cada frame de la long routine para mantener activa la pose que utiliza el sprite.&lt;br /&gt;
&lt;br /&gt;
=== Upload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; recibe en A, con 16 bits, el ID dinámico base del recurso y le suma el valor de &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    !Upload&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, si &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; contiene 0 se solicita la primera pose; si contiene 1 se solicita la pose siguiente, y así sucesivamente. Esto permite que la rutina de animación cambie solamente &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; mientras &amp;lt;code&amp;gt;PoseManagement&amp;lt;/code&amp;gt; conserva el mismo ID base.&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera a partir del DynamicInfo durante la instalación de Dynamic Xtreme y queda disponible en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones bajos y otros separadores, y escribiendo en mayúscula la inicial de cada palabra. Por ejemplo, &amp;lt;code&amp;gt;my_sprite.dynamicinfo&amp;lt;/code&amp;gt; genera el componente &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; devuelve el carry activado cuando existe una pose utilizable. Esta puede ser la pose solicitada durante el frame actual o la última pose válida del sprite, utilizada como respaldo mientras la nueva termina de cargarse. El carry se devuelve desactivado solamente cuando el sprite todavía no posee ninguna pose que pueda utilizar.&lt;br /&gt;
&lt;br /&gt;
Cuando la solicitud tiene éxito, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; guarda la pose realmente disponible y &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; guarda su posición dentro de la caché de VRAM. Por esta razón, el dibujo debe utilizar el estado de la última pose disponible y no asumir que &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; ya fue cargado.&lt;br /&gt;
&lt;br /&gt;
=== UploadWithoutPoseOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; también recibe un ID dinámico en A con 16 bits, pero lo utiliza directamente y no le suma &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite003&lt;br /&gt;
    !UploadWithoutPoseOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esta variante es útil cuando el código ya seleccionó el ID dinámico exacto, por ejemplo mediante una tabla o una condición propia. Su carry tiene el mismo significado que en &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;: activado cuando existe una pose utilizable y desactivado cuando todavía no existe ninguna.&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!DynamicPoseIDMySprite003&amp;lt;/code&amp;gt; también es generado desde el DynamicInfo y se encuentra en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre utiliza la misma normalización de estilo CamelCase: se eliminan los separadores y se escribe en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
Actualmente &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; está publicado por los archivos de defines para sprites normales y cluster sprites. Los extended sprites deben utilizar &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; junto con &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; mientras su archivo de defines no publique este alias.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; pertenecen al sistema de carga dinámica. No deben confundirse con los defines &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt; del DrawInfo, que se utilizan posteriormente para dibujar la pose.&lt;br /&gt;
&lt;br /&gt;
== Dibujar Poses en Pantalla ==&lt;br /&gt;
&lt;br /&gt;
Una vez que &amp;lt;code&amp;gt;PoseManagement&amp;lt;/code&amp;gt; ha obtenido una pose utilizable, esta puede dibujarse mediante &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt;. Ambas rutinas utilizan la posición, el volteo, la paleta y la pose dinámica que Dynamic Xtreme conserva para el sprite.&lt;br /&gt;
&lt;br /&gt;
Antes de llamar a cualquiera de las dos rutinas deben prepararse los siguientes valores:&lt;br /&gt;
&lt;br /&gt;
* A, con 16 bits, contiene el ID de la pose de dibujo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; contiene propiedades adicionales con el formato &amp;lt;code&amp;gt;YXCC----&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; indica la prioridad máxima que pueden utilizar los tiles de la pose.&lt;br /&gt;
&lt;br /&gt;
Los valores admitidos por &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; son:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;: prioridad máxima.&lt;br /&gt;
* &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt;: prioridad alta.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;: prioridad propia del tipo de sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt;: prioridad mínima.&lt;br /&gt;
&lt;br /&gt;
=== DXDraw ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; dibuja la pose tomando como origen la posición normal del sprite. Una rutina de dibujo básica puede escribirse de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDraw&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El valor de &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; se suma al primer ID de dibujo para seleccionar la pose que realmente se encuentra disponible. Es importante utilizar &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; y no &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;: mientras una pose nueva termina de cargarse, Dynamic Xtreme puede conservar la pose anterior como respaldo.&lt;br /&gt;
&lt;br /&gt;
Este ejemplo supone que las poses del DrawInfo siguen el mismo orden que las poses del DynamicInfo. Si el orden es diferente, el código debe convertir &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; al ID de dibujo correspondiente, por ejemplo mediante una tabla.&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; es generado a partir del DrawInfo durante la instalación y queda disponible en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres generados se normalizan eliminando espacios, guiones bajos y otros separadores, y escribiendo en mayúscula la inicial de cada palabra. Por ejemplo, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; genera el componente &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt; identifican poses de dibujo declaradas en un DrawInfo. No deben confundirse con los defines &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; del DynamicInfo, que se utilizan con &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; para solicitar los gráficos dinámicos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; combina las propiedades indicadas en &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt;, la paleta asignada y las propiedades propias de la pose. También utiliza &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; para localizar sus gráficos en la caché de VRAM. Si este valor contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, la rutina no dibuja nada.&lt;br /&gt;
&lt;br /&gt;
=== DXDrawWithOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; funciona de la misma forma, pero permite desplazar el dibujo con respecto a la posición del sprite. Los desplazamientos se entregan como valores de 8 bits con signo mediante &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$08&lt;br /&gt;
    STA !XOffsetParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$F8&lt;br /&gt;
    STA !YOffsetParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDrawWithOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, el dibujo se desplaza 8 píxeles hacia la derecha y 8 píxeles hacia arriba. Un valor positivo en X desplaza la pose hacia la derecha y uno negativo hacia la izquierda; en Y, un valor positivo la desplaza hacia abajo y uno negativo hacia arriba.&lt;br /&gt;
&lt;br /&gt;
El offset solamente modifica la posición donde se dibuja la pose. No cambia la posición real del sprite, su hitbox ni sus interacciones. Esto resulta útil para alinear gráficos, aplicar movimientos visuales o dibujar varias partes de una entidad desde una misma posición lógica.&lt;br /&gt;
&lt;br /&gt;
Al igual que en el ejemplo anterior, &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; es un define generado desde el DrawInfo y guardado en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre utiliza la normalización de Dynamic Xtreme: elimina separadores como espacios y guiones bajos, y escribe en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
=== DrawStatic ===&lt;br /&gt;
&lt;br /&gt;
El sistema de dibujo de Dynamic Xtreme también puede utilizarse con poses estáticas. Estas poses se declaran mediante &amp;lt;code&amp;gt;.IsStatic&amp;lt;/code&amp;gt; en el DrawInfo y se dibujan con la macro &amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt;. Como sus gráficos ya se encuentran disponibles en la VRAM, no necesitan &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cuando una pose estática utiliza el tile predeterminado (0) para todos sus componentes, el dibujo toma el número de tile desde &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, que representa la scratch RAM &amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;. Esto permite reutilizar una misma pose, por ejemplo una de un solo tile, para dibujar distintos gráficos. El sprite debe preparar el valor antes de llamar a &amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    LDA #$80            ; Número de tile que se desea dibujar&lt;br /&gt;
    STA !Tile           ; Scratch RAM $05&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Este valor debe prepararse en cada llamada de dibujo que lo necesite; no basta con establecerlo durante el INIT, porque la scratch RAM se comparte con otras rutinas.&lt;br /&gt;
&lt;br /&gt;
En las poses dinámicas, &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; obtienen el tile desde la ubicación de los gráficos en la caché de VRAM. En ese caso no es necesario preparar &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; manualmente. Si una pose estática declara tiles distintos del predeterminado en su DrawInfo, el dibujo utiliza esos valores directamente.&lt;br /&gt;
&lt;br /&gt;
El siguiente ejemplo dibuja una pose estática en la posición de un sprite normal, sin volteo y utilizando la paleta A:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    REP #$21&lt;br /&gt;
    LDA #!PoseIDMyStaticSprite_Frame0&lt;br /&gt;
    %DrawStatic(0, 1, #$00, #$04, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El primer parámetro indica si se utilizarán offsets adicionales: 0 dibuja en la posición entregada y 1 aplica también &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt;. Los parámetros siguientes proporcionan el contexto del dibujo, el volteo, la paleta y las posiciones X e Y de 16 bits. Las posiciones indexadas se escriben entre comillas para que la coma de &amp;lt;code&amp;gt;,x&amp;lt;/code&amp;gt; no sea interpretada como un separador de parámetros de la macro.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt; finaliza la rutina mediante &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;, por lo que no se coloca otro &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; después de la llamada en este ejemplo.&lt;br /&gt;
&lt;br /&gt;
En el ejemplo, &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; indica que la pose no se voltea y &amp;lt;code&amp;gt;#$04&amp;lt;/code&amp;gt; selecciona la paleta A. Estos argumentos también pueden utilizar tablas o variables cuando el sprite necesite cambiar su orientación o paleta.&lt;br /&gt;
&lt;br /&gt;
El define &amp;lt;code&amp;gt;!PoseIDMyStaticSprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo durante la instalación y queda disponible en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: se eliminan espacios, guiones bajos, guiones y otros separadores, y se escribe en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
Para obtener más información sobre la declaración de poses estáticas, consulta [[es/Dynamic_Xtreme_files_and_formats|Archivos y formatos de Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
== Instalar y probar el sprite ==&lt;br /&gt;
&lt;br /&gt;
Cada vez que se modifique alguno de los recursos procesados por Dynamic Xtreme, se debe reinstalar primero Dynamic Xtreme y después volver a insertar los sprites con PIXI. Esto incluye cambios en archivos &amp;lt;code&amp;gt;*.dynamicinfo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;*.drawinfo&amp;lt;/code&amp;gt;, gráficos &amp;lt;code&amp;gt;*.bin&amp;lt;/code&amp;gt;, efectos &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y cualquier otro recurso dinámico utilizado por el sprite.&lt;br /&gt;
&lt;br /&gt;
El orden es importante: Dynamic Xtreme debe procesar primero los recursos y regenerar sus datos y defines; después PIXI puede ensamblar el sprite utilizando la información actualizada.&lt;br /&gt;
&lt;br /&gt;
Si el único archivo modificado es el código &amp;lt;code&amp;gt;*.asm&amp;lt;/code&amp;gt; del sprite, no es necesario reinstalar Dynamic Xtreme. En ese caso basta con ejecutar PIXI nuevamente.&lt;br /&gt;
&lt;br /&gt;
Para conocer el proceso completo de instalación, configuración y reinstalación de recursos, consulta la [[Dynamic_Xtreme_Quick_Start|guía de inicio rápido de Dynamic Xtreme]].&lt;br /&gt;
&lt;br /&gt;
Después de cada instalación, prueba el sprite en el juego y comprueba que sus poses, paletas, volteos y desplazamientos se muestren correctamente durante sus diferentes estados y animaciones.&lt;br /&gt;
&lt;br /&gt;
== Errores comunes ==&lt;br /&gt;
&lt;br /&gt;
=== Utilizar un nombre sin normalizar en un define generado ===&lt;br /&gt;
&lt;br /&gt;
Los nombres incluidos en los defines generados por Dynamic Xtreme deben escribirse con la normalización utilizada por la herramienta. Los espacios, guiones bajos y guiones se eliminan, y la primera letra de cada palabra se escribe en mayúscula siguiendo el estilo PascalCase.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, una pose llamada &amp;lt;code&amp;gt;my_sprite-pose&amp;lt;/code&amp;gt; utiliza el componente normalizado &amp;lt;code&amp;gt;MySpritePose&amp;lt;/code&amp;gt; dentro de un define como el siguiente:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!DynamicPoseIDMySpritePose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Escribir el nombre original con sus separadores, utilizar una combinación distinta de mayúsculas o confundir un define &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; con un &amp;lt;code&amp;gt;!PoseID...&amp;lt;/code&amp;gt; hará que Asar no encuentre el símbolo. Ante una duda, revisa el nombre exacto generado en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Inicializar incorrectamente las variables del sprite ===&lt;br /&gt;
&lt;br /&gt;
Las variables utilizadas por Dynamic Xtreme deben recibir valores válidos cada vez que se crea un sprite. Cuando se utiliza &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt; deben comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, mientras que variables como &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LocalFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt; normalmente comienzan en 0. También deben configurarse las distancias utilizadas por &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Si estas tablas no se inicializan correctamente, el sprite puede reutilizar una paleta, una pose o información dejada por otro sprite que ocupó anteriormente el mismo slot. En cluster sprites y extended sprites, esta inicialización debe realizarse mediante la rutina de inicio simulada explicada anteriormente.&lt;br /&gt;
&lt;br /&gt;
=== No reservar un Extra Byte para la paleta ===&lt;br /&gt;
&lt;br /&gt;
Un sprite normal que utilice carga de paletas debe tener disponible al menos un Extra Byte en su archivo &amp;lt;code&amp;gt;*.cfg&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;*.json&amp;lt;/code&amp;gt;. Dynamic Xtreme utiliza &amp;lt;code&amp;gt;Extra Byte 1&amp;lt;/code&amp;gt; como &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt; y, normalmente, también aprovecha sus cuatro bits bajos para seleccionar &amp;lt;code&amp;gt;!Version&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Si el sprite no declara ningún Extra Byte, &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt; no contendrá la configuración necesaria para seleccionar correctamente la paleta y la versión del sprite.&lt;br /&gt;
&lt;br /&gt;
=== No restaurar una paleta fija en la short routine ===&lt;br /&gt;
&lt;br /&gt;
Un sprite puede utilizar una paleta fija que ya se encuentre cargada en el nivel en lugar de llamar a &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;. En este caso todavía es necesario asignar manualmente a &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; el valor de la paleta que utilizará el dibujo.&lt;br /&gt;
&lt;br /&gt;
Los valores avanzan de dos en dos y corresponden a las paletas de sprites 8-F:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;: paleta 8.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;: paleta 9.&lt;br /&gt;
* &amp;lt;code&amp;gt;$04&amp;lt;/code&amp;gt;: paleta A.&lt;br /&gt;
* &amp;lt;code&amp;gt;$06&amp;lt;/code&amp;gt;: paleta B.&lt;br /&gt;
* &amp;lt;code&amp;gt;$08&amp;lt;/code&amp;gt;: paleta C.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;: paleta D.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0C&amp;lt;/code&amp;gt;: paleta E.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt;: paleta F.&lt;br /&gt;
&lt;br /&gt;
El valor debe asignarse durante el &amp;lt;code&amp;gt;INIT&amp;lt;/code&amp;gt; y también dentro de la short routine. Cuando &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; envía el sprite a la short routine, invalida &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;; por eso la paleta fija debe restaurarse en esa ruta:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
; Dentro de INIT&lt;br /&gt;
    LDA #$04            ; Paleta A&lt;br /&gt;
    STA !Palette,x&lt;br /&gt;
&lt;br /&gt;
; Dentro de SpriteCode&lt;br /&gt;
.ShortRoutine&lt;br /&gt;
    LDA #$04            ; Paleta A&lt;br /&gt;
    STA !Palette,x&lt;br /&gt;
&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    %SubOffScreen()&lt;br /&gt;
    ; Aquí va la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esta asignación manual solamente corresponde a sprites que utilizan una paleta fija y no llaman a &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;. Los sprites con carga dinámica deben conservar el flujo de asignación explicado en la sección de manejo de paletas.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
	<entry>
		<id>https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_ASM_API&amp;diff=21350</id>
		<title>es/Dynamic Xtreme ASM API</title>
		<link rel="alternate" type="text/html" href="https://sneslab.net/mw/index.php?title=es/Dynamic_Xtreme_ASM_API&amp;diff=21350"/>
		<updated>2026-10-24T04:38:19Z</updated>

		<summary type="html">&lt;p&gt;Anonimzwx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Select Language|Dynamic_Xtreme_ASM_API}}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Para aprender a organizar un sprite completo, consulta la [[es/Dynamic_Xtreme_sprite_creation_guide|guía de creación de sprites]].&lt;br /&gt;
&lt;br /&gt;
== Rutinas para sprites ==&lt;br /&gt;
&lt;br /&gt;
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: &amp;lt;code&amp;gt;NormalSpriteDefines.asm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ClusterSpriteDefines.asm&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt;. La ruta del include es relativa al archivo ASM del sprite.&lt;br /&gt;
&lt;br /&gt;
Para usar llamadas como &amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, escribe su nombre directamente, como muestran los ejemplos. No añadas &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt; ni &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt; delante. Salvo que se indique lo contrario, X debe contener el número del slot que ocupa el sprite.&lt;br /&gt;
&lt;br /&gt;
=== RenderBox ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!RenderBox&amp;lt;/code&amp;gt; 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).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedRenderBox()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!RenderXDistanceOutOfScreen,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderYDistanceOutOfScreen,x&amp;lt;/code&amp;gt;: distancias horizontal y vertical permitidas fuera de la pantalla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite está en pantalla o dentro de la distancia permitida fuera de sus bordes; se debe ejecutar la long routine.&lt;br /&gt;
* Carry desactivado: el sprite está demasiado lejos de la pantalla para dibujarse; se debe ejecutar la short routine.&lt;br /&gt;
&lt;br /&gt;
Cuando el sprite está demasiado lejos, establece &amp;lt;code&amp;gt;!Palette&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastVersion&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Esto indica que deberá volver a obtener su paleta y su pose cuando se acerque a la pantalla. También guarda en &amp;lt;code&amp;gt;!LastFlip&amp;lt;/code&amp;gt; el volteo que resulta de combinar &amp;lt;code&amp;gt;!GlobalFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip&amp;lt;/code&amp;gt;. En sprites normales actualiza además las variables que indican si está fuera de pantalla horizontal o verticalmente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
print &amp;quot;INIT &amp;quot;,pc&lt;br /&gt;
    LDA.b #!RenderBoxXDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderXDistanceOutOfScreen,x&lt;br /&gt;
    LDA.b #!RenderBoxYDistanceOutOfScreenMySprite&lt;br /&gt;
    STA !RenderYDistanceOutOfScreen,x&lt;br /&gt;
    ; Aquí va el resto de la inicialización del sprite&lt;br /&gt;
RTL&lt;br /&gt;
&lt;br /&gt;
SpriteCode:&lt;br /&gt;
    !RenderBox&lt;br /&gt;
    BCS .LongRoutine&lt;br /&gt;
&lt;br /&gt;
.ShortRoutine&lt;br /&gt;
    LDA #$00&lt;br /&gt;
    %SubOffScreen()&lt;br /&gt;
    ; Aquí va la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&lt;br /&gt;
.LongRoutine&lt;br /&gt;
    ; Aquí van el manejo de paletas, poses y dibujo&lt;br /&gt;
    ; y la lógica de tu sprite&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La llamada a &amp;lt;code&amp;gt;%SubOffScreen()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Los defines &amp;lt;code&amp;gt;!RenderBoxXDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!RenderBoxYDistanceOutOfScreenMySprite&amp;lt;/code&amp;gt; se generan desde el DrawInfo y se guardan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. 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, &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Si el sprite utiliza varios DrawInfo, utiliza la mayor distancia horizontal y la mayor distancia vertical entre ellos.&lt;br /&gt;
&lt;br /&gt;
=== PaletteAssignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt; selecciona una paleta del DynamicInfo usando &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
Si el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; está activado (&amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;), también procesa los efectos globales de paleta correspondientes. Si está desactivado, la paleta queda excluida del efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cómo se elige la paleta&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; indica qué paleta de sprites se permite utilizar y si sus colores reciben el efecto global. Su formato es &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt;: 0 excluye la paleta del efecto global; 1 permite aplicarlo.&lt;br /&gt;
* &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt;: con asignación manual, selecciona una paleta entre 8 y F. &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; elige la 8, &amp;lt;code&amp;gt;001&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* Con asignación automática, &amp;lt;code&amp;gt;PPP = 000&amp;lt;/code&amp;gt; permite buscar entre las ocho paletas. Un valor &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; limita la búsqueda a las paletas 8-B; un valor &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; la limita a las C-F.&lt;br /&gt;
* Los cuatro bits bajos no se utilizan para estas opciones.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; decide quién elige el destino y si se cargan colores. Su formato es &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 00&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;): automático. Dynamic Xtreme elige una de las paletas permitidas y carga los colores del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 01&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt;): manual. Utiliza la paleta indicada en &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; y carga los colores del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;AA = 10&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt;): manual sin carga. Utiliza la paleta indicada en &amp;lt;code&amp;gt;PPP&amp;lt;/code&amp;gt; con los colores que ya tiene el nivel.&lt;br /&gt;
&lt;br /&gt;
En sprites normales, &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; es &amp;lt;code&amp;gt;!ExtraByte1,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; es &amp;lt;code&amp;gt;!ExtraProp2,x&amp;lt;/code&amp;gt;. Lo habitual es usar el primer Extra Byte con formato &amp;lt;code&amp;gt;EPPPVVVV&amp;lt;/code&amp;gt; y copiar sus cuatro bits bajos a &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, con asignación manual, &amp;lt;code&amp;gt;!PaletteOption,x = $A0&amp;lt;/code&amp;gt; utiliza la paleta A y permite el efecto global. Si &amp;lt;code&amp;gt;!Version,x = 1&amp;lt;/code&amp;gt;, carga en ella la segunda paleta de la lista del DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedPaletteAssignment()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; correspondiente al DynamicInfo que contiene las paletas.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;: índice de la paleta dentro de la tabla.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: última versión procesada. Se compara con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; para detectar cambios y debe inicializarse en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;: selección de paleta y participación en el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt;: asignación automática, manual o manual sin carga.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite puede dibujarse con la paleta asignada.&lt;br /&gt;
* Carry desactivado: el sprite todavía no tiene una paleta lista para dibujar.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta asignada, con valores de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos para las paletas 8-F.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: se actualiza con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; cuando se procesa la nueva asignación.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignment&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre del recurso se normaliza en PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== PaletteAssignmentNoUpload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; elige la paleta igual que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
El bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;) 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 &amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; elige la paleta del DynamicInfo: 0 para la primera, 1 para la segunda, etc. &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: 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, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; elige el destino automáticamente, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; usa el indicado en PPP y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedPaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!PaletteAssignmentOption,x&amp;lt;/code&amp;gt;: mismas opciones que en &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: última versión procesada, utilizada para detectar cambios respecto de &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;. Debe inicializarse en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite tiene una paleta asignada; desactivado si no pudo obtenerse.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta asignada.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastVersion,x&amp;lt;/code&amp;gt;: se actualiza con &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt; cuando se procesa la nueva asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: número que identifica la paleta elegida del DynamicInfo, cuando se utiliza un modo que carga sus colores.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base en ROM.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    ; Aquí se prepara y concatena el efecto.&lt;br /&gt;
    ; Conserva Y y la dirección de $02-$04 para esa llamada.&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; dice qué paleta del DynamicInfo se eligió; &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; dice cuál de las paletas 8-F utilizará el sprite para dibujarse. Los datos de &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;, eliminando los separadores.&lt;br /&gt;
&lt;br /&gt;
=== Upload ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt; consigue los gráficos de la pose que el sprite quiere mostrar. La pose se selecciona sumando &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedUpload()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico base.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PoseIndex,x&amp;lt;/code&amp;gt;: índice que se suma al ID base.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt;: volteos que se combinarán para dibujar.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* Carry desactivado: el sprite todavía no tiene una pose disponible.&lt;br /&gt;
* &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt;: estado de la pose disponible para dibujar.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    !Upload&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== UploadWithoutPoseOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt; solicita directamente el ID dinámico entregado en A, sin sumarle &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt;. Como &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;, reutiliza los gráficos si ya están en VRAM y puede seguir mostrando la pose anterior mientras no consiga cargar la nueva.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: existe &amp;lt;code&amp;gt;%DXExtendedUploadWithoutPoseOffset()&amp;lt;/code&amp;gt;, pero actualmente &amp;lt;code&amp;gt;ExtendedSpriteDefines.asm&amp;lt;/code&amp;gt; no publica el alias &amp;lt;code&amp;gt;!UploadWithoutPoseOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico exacto.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!GlobalFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LocalFlip,x&amp;lt;/code&amp;gt;: volteos del sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: el sprite tiene una pose disponible para dibujar; desactivado si todavía no tiene ninguna.&lt;br /&gt;
* Guarda la pose que se puede dibujar en &amp;lt;code&amp;gt;!LastPoseIndex,x&amp;lt;/code&amp;gt; y la ubicación de sus gráficos en &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;, igual que &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite003&lt;br /&gt;
    !UploadWithoutPoseOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite003&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== DXDraw ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; dibuja una pose utilizando los gráficos dinámicos disponibles para el sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedDraw()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID de la pose de dibujo.&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;): propiedades adicionales, con formato &amp;lt;code&amp;gt;YXCC----&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;): prioridad máxima de los tiles; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; máxima, &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; alta, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; propia del tipo de sprite y &amp;lt;code&amp;gt;$03&amp;lt;/code&amp;gt; mínima.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!LastFlip,x&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt;: paleta, volteo y ubicación de los gráficos disponibles.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose en pantalla. Si &amp;lt;code&amp;gt;!LastPoseHashIndex,x&amp;lt;/code&amp;gt; contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no dibuja. A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDraw&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, las poses deben estar en el mismo orden en el DrawInfo y el DynamicInfo. Se utiliza &amp;lt;code&amp;gt;!LastPoseIndex&amp;lt;/code&amp;gt; porque indica qué pose se puede dibujar: si la nueva todavía no se pudo cargar, seguirá mostrando la anterior.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres de recurso y pose se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Este ID de dibujo es distinto de los IDs &amp;lt;code&amp;gt;!DynamicPoseID...&amp;lt;/code&amp;gt; del DynamicInfo.&lt;br /&gt;
&lt;br /&gt;
=== DXDrawWithOffset ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedDrawWithOffset()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Las mismas entradas de &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;): desplazamiento horizontal de 8 bits con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;): desplazamiento vertical de 8 bits con signo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja igual que &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;, pero suma los desplazamientos que preparaste. Un valor positivo en &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; mueve el dibujo a la derecha; en &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt;, hacia abajo. Los valores negativos lo mueven a la izquierda o hacia arriba.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Draw:&lt;br /&gt;
    LDA #$08&lt;br /&gt;
    STA !XOffsetParam&lt;br /&gt;
    LDA #$F8&lt;br /&gt;
    STA !YOffsetParam&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
&lt;br /&gt;
    LDA !LastPoseIndex,x&lt;br /&gt;
    REP #$21&lt;br /&gt;
    AND #$00FF&lt;br /&gt;
    ADC #!PoseIDMySprite_Frame0&lt;br /&gt;
    !DXDrawWithOffset&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo desplaza el dibujo 8 píxeles a la derecha y 8 hacia arriba. &amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; el nombre se normaliza en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ReplacePalette ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Suele utilizarse después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;: primero se asigna la paleta sin cargar sus colores y después se reemplazan por los que quieres mostrar. Antes de llamar a &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, coloca en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; la dirección de los nuevos colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedReplacePalette()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* X: índice del sprite.&lt;br /&gt;
* A en modo de 8 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de la nueva paleta en BGR555.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt;: paleta ya asignada.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption,x&amp;lt;/code&amp;gt;: participación en el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta; si los nuevos colores todavía no están listos, se conservan los anteriores.&lt;br /&gt;
* Carry desactivado: la paleta todavía no tiene colores listos para dibujar.&lt;br /&gt;
&lt;br /&gt;
Mantiene el mismo ID de paleta, pero solicita cambiar sus colores. Al marcar que el efecto debe volver a calcularse, utiliza &amp;lt;code&amp;gt;$FFFF&amp;lt;/code&amp;gt; si nunca se habían obtenido colores para dibujar, o &amp;lt;code&amp;gt;$FFFE&amp;lt;/code&amp;gt; si puede seguir mostrando los anteriores mientras prepara los nuevos.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ReplaceSpritePalette:&lt;br /&gt;
    ; Ejecutar cuando se necesite cambiar una paleta ya asignada.&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;8&lt;br /&gt;
    STA $03&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
    !ReplacePalette&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyAlternatePalette&amp;lt;/code&amp;gt; es la dirección de una paleta insertada desde los recursos declarados en un DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_alternate_palette&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyAlternatePalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ConcatenateRGBPaletteEffectToGlobal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, y después aplica el global sobre ese resultado. Llámala después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, que deja preparada la paleta original.&lt;br /&gt;
&lt;br /&gt;
El uso habitual es asignar primero la paleta con &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; y, si el carry está activado, llamar a esta rutina para aplicar los efectos y completar la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID del efecto local RGB.&lt;br /&gt;
* X de 8 bits: copia aquí el valor de &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;LDA !Palette,x&amp;lt;/code&amp;gt; seguido de &amp;lt;code&amp;gt;TAX&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
* Y de 8 bits: conserva el valor que dejó &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;. El valor 1 obliga a calcular de nuevo el efecto; 0 permite reutilizar el resultado anterior si no cambió nada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base BGR555 preparada por la asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;: el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; debe estar activado para combinar con el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta. Si el nuevo efecto todavía no está listo, se sigue mostrando el anterior.&lt;br /&gt;
* Carry desactivado: todavía no hay colores listos para dibujar esa paleta.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyRGBEffect0&lt;br /&gt;
    !ConcatenateRGBPaletteEffectToGlobal&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y &amp;lt;code&amp;gt;!PaletteEffectIDMyRGBEffect0&amp;lt;/code&amp;gt; desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. Ambos quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus nombres se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. Si se necesita Y para seleccionar el efecto mediante una tabla, conserva su valor con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; y restáuralo con &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; antes de concatenar.&lt;br /&gt;
&lt;br /&gt;
=== ConcatenateHSLPaletteEffectToGlobal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ConcatenateHSLPaletteEffectToGlobal&amp;lt;/code&amp;gt; permite que la paleta del sprite tenga un efecto HSL propio, como &amp;lt;code&amp;gt;MixH&amp;lt;/code&amp;gt;, y siga siendo afectada por el efecto global. Primero aplica el efecto local y después el global. Llámala después de &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, que deja preparada la paleta original.&lt;br /&gt;
&lt;br /&gt;
El uso habitual es asignar primero la paleta con &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt; y, si el carry está activado, llamar a esta rutina para aplicar los efectos y completar la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rutina utilizada según el tipo de sprite&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Sprite normal: &amp;lt;code&amp;gt;%DXNormalConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Cluster sprite: &amp;lt;code&amp;gt;%DXClusterConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Extended sprite: &amp;lt;code&amp;gt;%DXExtendedConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID del efecto local HSL.&lt;br /&gt;
* X de 8 bits: copia aquí el valor de &amp;lt;code&amp;gt;!Palette,x&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;LDA !Palette,x&amp;lt;/code&amp;gt; seguido de &amp;lt;code&amp;gt;TAX&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
* Y de 8 bits: conserva el valor que dejó &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;. El valor 1 obliga a calcular de nuevo el efecto; 0 permite reutilizar el resultado anterior si no cambió nada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de la paleta base BGR555 preparada por la asignación.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PaletteOption&amp;lt;/code&amp;gt;: el bit &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; debe estar activado para combinar con el efecto global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: se puede dibujar con la paleta. Si el nuevo efecto todavía no está listo, se sigue mostrando el anterior.&lt;br /&gt;
* Carry desactivado: todavía no hay colores listos para dibujar esa paleta.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    !PaletteAssignmentNoUpload&lt;br /&gt;
    BCC .Return&lt;br /&gt;
&lt;br /&gt;
    LDA !Palette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyHSLEffect0&lt;br /&gt;
    !ConcatenateHSLPaletteEffectToGlobal&lt;br /&gt;
.Return&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y &amp;lt;code&amp;gt;!PaletteEffectIDMyHSLEffect0&amp;lt;/code&amp;gt; desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. Quedan en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; y utilizan nombres normalizados en PascalCase: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra. Conserva Y con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; si lo utilizas temporalmente para seleccionar el efecto.&lt;br /&gt;
&lt;br /&gt;
Ambas variantes de concatenación realizan las conversiones necesarias si el efecto local y el global utilizan espacios de color diferentes. Consulta [[es/Dynamic_Xtreme_files_and_formats#Tipos_de_efectos|Tipos de efectos]] para identificar los efectos RGB y HSL.&lt;br /&gt;
&lt;br /&gt;
== Rutinas y Macros Generales ==&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!NormalPoseIndex,x&amp;lt;/code&amp;gt;, escríbelo entre comillas para que Asar lo lea como un solo argumento. Utiliza &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; al entregar un valor inmediato, como &amp;lt;code&amp;gt;#$04&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Poses dinámicas ===&lt;br /&gt;
&lt;br /&gt;
==== DynamicPoseSpaceConfig ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !DynamicPoseSpaceConfig&amp;lt;/code&amp;gt; elige qué partes de la memoria gráfica (VRAM) puede usar Dynamic Xtreme para cargar poses dinámicas. Normalmente se llama desde el &amp;lt;code&amp;gt;init&amp;lt;/code&amp;gt; de UberASM al entrar al nivel.&lt;br /&gt;
&lt;br /&gt;
Los defines con las configuraciones disponibles se encuentran en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, bajo los nombres &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 8 bits: una de las configuraciones &amp;lt;code&amp;gt;!DynamicSpaceConfig...&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Sus valores van de &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;$1C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
init:&lt;br /&gt;
    LDA #!DynamicSpaceConfigSP4&lt;br /&gt;
    JSL !DynamicPoseSpaceConfig&lt;br /&gt;
RTL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicSpaceConfigSP4&amp;lt;/code&amp;gt; es una constante publicada en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; que permite utilizar SP4. Otras opciones incluyen &amp;lt;code&amp;gt;!DynamicSpaceConfigSP3&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!DynamicSpaceConfigSP34&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DynamicSpaceConfigSP234&amp;lt;/code&amp;gt;. Selecciona una región que no se superponga con los gráficos estáticos utilizados por el nivel.&lt;br /&gt;
&lt;br /&gt;
==== TakeDynamicRequest ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !TakeDynamicRequest&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Y de 16 bits: ID exacto de la pose dinámica.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RequestPose:&lt;br /&gt;
    REP #$10&lt;br /&gt;
    LDY #!DynamicPoseIDMySprite000&lt;br /&gt;
    JSL !TakeDynamicRequest&lt;br /&gt;
    BCC .Unavailable&lt;br /&gt;
&lt;br /&gt;
    ; X contiene el índice hash de la pose solicitada.&lt;br /&gt;
    ; Aquí tu código puede guardar ese índice para dibujar la pose.&lt;br /&gt;
RTS&lt;br /&gt;
.Unavailable&lt;br /&gt;
    ; Aquí se maneja la falta de recursos.&lt;br /&gt;
RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores y escribiendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== DynamicRoutine ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSL !DynamicRoutine&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; prepara esos datos antes de llamarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Datos que necesita la llamada&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 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.&lt;br /&gt;
* &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt;: variable interna de 16 bits que contiene el ID de la pose que se va a copiar.&lt;br /&gt;
* 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.&lt;br /&gt;
&lt;br /&gt;
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. &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; realiza ambas tareas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo de funcionamiento&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Cuando un sprite solicita una pose que todavía no está en VRAM, &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt; busca dónde colocarla. Después guarda su ID en &amp;lt;code&amp;gt;PoseIDBackup&amp;lt;/code&amp;gt; y llama a &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; con la posición elegida en A. Esta última prepara la copia de los gráficos; el NMI ejecuta la transferencia.&lt;br /&gt;
&lt;br /&gt;
Para cargar una pose desde el código de un sprite, utiliza &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. Si necesitas hacer la solicitud directamente mediante su ID, utiliza &amp;lt;code&amp;gt;!TakeDynamicRequest&amp;lt;/code&amp;gt;. Llamar a &amp;lt;code&amp;gt;!DynamicRoutine&amp;lt;/code&amp;gt; requiere preparar también la variable interna del ID, el banco de datos y el espacio de destino descritos arriba.&lt;br /&gt;
&lt;br /&gt;
==== GeneralUpload ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%GeneralUpload(Pose16, checkLast, sprite, flip, safeCheck, withoutOffset,&lt;br /&gt;
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,&lt;br /&gt;
    globalFlip, localFlip, lastFlip)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La firma anterior muestra el orden de los parámetros; escribe la llamada en una sola línea.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Pose16&amp;lt;/code&amp;gt;: 0 utiliza índices de pose de 8 bits; 1 utiliza índices de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt;: 1 permite seguir dibujando la pose anterior si no se pudo obtener la nueva; 0 desactiva esa opción.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 0 para usar variables propias sin recuperar el índice del sprite; 1 para trabajar con las tablas del sprite, recuperando X desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 2 funciona como 1, pero solicita la pose sin comparar ni cambiar &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;flip&amp;lt;/code&amp;gt;: 1 combina &amp;lt;code&amp;gt;globalFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;localFlip&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;; 0 omite esa actualización.&lt;br /&gt;
* &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt;: 1 evita repetir la solicitud en el mismo frame utilizando &amp;lt;code&amp;gt;safeLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;safeHigh&amp;lt;/code&amp;gt;; 0 omite la comprobación.&lt;br /&gt;
* &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;: 0 suma &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt; al ID base; 1 utiliza directamente el ID recibido.&lt;br /&gt;
* &amp;lt;code&amp;gt;safeLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;safeHigh&amp;lt;/code&amp;gt;: variables que guardan los bytes bajo y alto del frame de la solicitud. Se escriben incluso cuando &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; es 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt;: variable del índice de pose deseado.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt;: variable del último índice de pose disponible.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;: variable que identifica la entrada donde Dynamic Xtreme guarda la ubicación de los gráficos en VRAM. &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt; indica que todavía no hay gráficos disponibles.&lt;br /&gt;
* &amp;lt;code&amp;gt;globalFlip&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;localFlip&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variables del volteo global, local y efectivo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada adicional&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID dinámico base o exacto, según &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Para &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; debe contener el índice del sprite.&lt;br /&gt;
&lt;br /&gt;
Con &amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt;, la macro solicita la pose aunque &amp;lt;code&amp;gt;poseIndex&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sean iguales, y deja &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sin modificar. Si consigue los gráficos, guarda su ubicación en &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;. Si la solicitud falla y &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; es 1, puede seguir usando los gráficos anteriores. &amp;lt;code&amp;gt;safeCheck&amp;lt;/code&amp;gt; sigue controlando si se permite repetir la solicitud durante el mismo frame.&lt;br /&gt;
&lt;br /&gt;
Este valor 2 no cambia el tamaño de los índices. Para utilizar variables de índice de 16 bits se selecciona &amp;lt;code&amp;gt;Pose16 = 1&amp;lt;/code&amp;gt;. El ID dinámico entregado en A siempre es de 16 bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sprite = 2&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Devuelve el carry activado cuando hay una pose disponible para dibujar: la solicitada o la anterior si &amp;lt;code&amp;gt;checkLast&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; al final; colócala al final de una rutina llamada con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %GeneralUpload(0, 1, 1, 1, 1, 0, &amp;quot;!NormalSafeFrameLowByte,x&amp;quot;, &amp;quot;!NormalSafeFrameHighByte,x&amp;quot;, &amp;quot;!NormalPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalGlobalFlip,x&amp;quot;, &amp;quot;!NormalLocalFlip,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las tablas de un sprite normal y un índice de pose de 8 bits. &amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;; el nombre se normaliza en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Upload (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%Upload()&amp;lt;/code&amp;gt; es la variante de &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; para índices de pose de 8 bits. No debe confundirse con el alias para sprites &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Upload(sprite, checkLast, flip, safeCheck, withoutOffset,&lt;br /&gt;
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,&lt;br /&gt;
    globalFlip, localFlip, lastFlip)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Recibe los mismos datos que &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt;, pero los índices guardados en las variables siempre son de 8 bits. La macro ya incluye el &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
El parámetro &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt; también admite 2: omite la comparación con &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; y no actualiza esa variable, pero sí actualiza &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt; al obtener la pose. No habilita índices de 16 bits; para eso se utiliza &amp;lt;code&amp;gt;%GeneralUpload()&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;Pose16 = 1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;lastPoseIndex&amp;lt;/code&amp;gt; sin modificar, el código del sprite puede controlar ese cambio.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %Upload(1, 1, 1, 1, 0, &amp;quot;!NormalSafeFrameLowByte,x&amp;quot;, &amp;quot;!NormalSafeFrameHighByte,x&amp;quot;, &amp;quot;!NormalPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseIndex,x&amp;quot;, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalGlobalFlip,x&amp;quot;, &amp;quot;!NormalLocalFlip,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; es generado desde el DynamicInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpriteUpload ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpriteUpload(withoutOffset, type)&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;withoutOffset&amp;lt;/code&amp;gt;: 0 suma &amp;lt;code&amp;gt;!PoseIndex&amp;lt;/code&amp;gt; al ID base; 1 utiliza el ID exacto.&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A de 16 bits: ID dinámico.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* Tablas de poses y volteo de Dynamic Xtreme del tipo seleccionado, inicializadas como en las rutinas &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PoseManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!DynamicPoseIDMySprite000&lt;br /&gt;
    %StandardSpriteUpload(0, &amp;quot;Normal&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!DynamicPoseIDMySprite000&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;, eliminando los separadores.&lt;br /&gt;
&lt;br /&gt;
=== Dibujo de poses ===&lt;br /&gt;
&lt;br /&gt;
Las macros de esta categoría terminan la rutina que las contiene mediante &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt;. Los ejemplos deben llamarse con &amp;lt;code&amp;gt;JSR&amp;lt;/code&amp;gt;. A debe contener el ID de dibujo con 16 bits; &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;) se preparan igual que para &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Draw ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%Draw()&amp;lt;/code&amp;gt; dibuja una pose dinámica. En la llamada indicas qué gráficos usar, su paleta, su volteo y la posición donde quieres dibujarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Draw(offset, sprite, lastPoseHashIndex, lastFlip, palette, xl, xh, yl, yh)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 utiliza las coordenadas entregadas; 1 añade &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;), de 8 bits con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 recupera el índice del sprite en X desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; antes de leer su paleta y posición; 0 omite ese paso.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;: variable que identifica dónde están registrados los gráficos de la pose en Dynamic Xtreme. Si contiene &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;, no se dibuja.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variable o valor que indica el volteo con el que se dibujará.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de la paleta; &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; selecciona la 8, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* &amp;lt;code&amp;gt;xl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;xh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición X.&lt;br /&gt;
* &amp;lt;code&amp;gt;yl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;yh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose con los gráficos indicados por &amp;lt;code&amp;gt;lastPoseHashIndex&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMySprite_Frame0&lt;br /&gt;
    %Draw(0, 1, &amp;quot;!NormalLastPoseHashIndex,x&amp;quot;, &amp;quot;!NormalLastFlip,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y se guarda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Los nombres se normalizan en PascalCase eliminando separadores, como &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;. El ID debe corresponder a los gráficos dinámicos disponibles.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpriteDraw ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpriteDraw(offset, type)&amp;lt;/code&amp;gt; dibuja una pose dinámica utilizando las tablas de Dynamic Xtreme del tipo de sprite seleccionado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 sin desplazamiento adicional; 1 utiliza los offsets de &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A de 16 bits: ID de dibujo.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt;: propiedades y prioridad.&lt;br /&gt;
* Las tablas de paleta, último volteo e índice hash de Dynamic Xtreme del tipo seleccionado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;%Draw()&amp;lt;/code&amp;gt;, utilizando las tablas estándar. Es la macro que utilizan las rutinas PIXI &amp;lt;code&amp;gt;!DXDraw&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!DXDrawWithOffset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para sprites normales, las rutinas PIXI preparan los aliases de coordenadas &amp;lt;code&amp;gt;!NormalXLow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!NormalXHigh&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!NormalYLow&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!NormalYHigh&amp;lt;/code&amp;gt;. Si se expande la macro directamente, también deben estar definidos, como en este ejemplo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!NormalXLow = !SpriteXLow&lt;br /&gt;
!NormalXHigh = !SpriteXHigh&lt;br /&gt;
!NormalYLow = !SpriteYLow&lt;br /&gt;
!NormalYHigh = !SpriteYHigh&lt;br /&gt;
&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMySprite_Frame0&lt;br /&gt;
    %StandardSpriteDraw(0, &amp;quot;Normal&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PoseIDMySprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== DrawStatic ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DrawStatic()&amp;lt;/code&amp;gt; dibuja una pose estática, declarada con &amp;lt;code&amp;gt;.IsStatic&amp;lt;/code&amp;gt; en el DrawInfo. Sus gráficos deben estar previamente cargados en las posiciones de VRAM indicadas por sus tiles.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%DrawStatic(offset, sprite, lastFlip, palette, xl, xh, yl, yh)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: 0 sin desplazamiento adicional; 1 utiliza &amp;lt;code&amp;gt;!XOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!YOffsetParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$8B&amp;lt;/code&amp;gt;), con signo.&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: parámetro conservado en la firma; la implementación actual de esta macro no lo utiliza.&lt;br /&gt;
* &amp;lt;code&amp;gt;lastFlip&amp;lt;/code&amp;gt;: variable o valor que indica el volteo; &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; dibuja sin volteo.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de paleta: &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt; selecciona la 8, &amp;lt;code&amp;gt;#$02&amp;lt;/code&amp;gt; la 9, y así hasta &amp;lt;code&amp;gt;#$0E&amp;lt;/code&amp;gt; para la F.&lt;br /&gt;
* &amp;lt;code&amp;gt;xl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;xh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición X.&lt;br /&gt;
* &amp;lt;code&amp;gt;yl&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;yh&amp;lt;/code&amp;gt;: variables o valores de los bytes bajo y alto de la posición Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas adicionales&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: ID de dibujo estático.&lt;br /&gt;
* &amp;lt;code&amp;gt;!PropParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$52&amp;lt;/code&amp;gt;) y &amp;lt;code&amp;gt;!MaxTilePriorityParam&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0A&amp;lt;/code&amp;gt;): propiedades y prioridad.&lt;br /&gt;
* &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$05&amp;lt;/code&amp;gt;): 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dibuja la pose sin consultar la caché de gráficos dinámicos. No requiere &amp;lt;code&amp;gt;!LastPoseHashIndex&amp;lt;/code&amp;gt; ni una llamada previa a &amp;lt;code&amp;gt;!Upload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
DrawPose:&lt;br /&gt;
    LDA #$80&lt;br /&gt;
    STA !Tile&lt;br /&gt;
    LDA #$20&lt;br /&gt;
    STA !PropParam&lt;br /&gt;
    LDA #$02&lt;br /&gt;
    STA !MaxTilePriorityParam&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PoseIDMyStaticSprite_Frame0&lt;br /&gt;
    %DrawStatic(0, 1, #$00, #$04, &amp;quot;!SpriteXLow,x&amp;quot;, &amp;quot;!SpriteXHigh,x&amp;quot;, &amp;quot;!SpriteYLow,x&amp;quot;, &amp;quot;!SpriteYHigh,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza el tile &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; si la pose está configurada para tomarlo desde &amp;lt;code&amp;gt;!Tile&amp;lt;/code&amp;gt;, sin volteo y con la paleta A. &amp;lt;code&amp;gt;!PoseIDMyStaticSprite_Frame0&amp;lt;/code&amp;gt; se genera desde el DrawInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_static_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyStaticSprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Paletas ===&lt;br /&gt;
&lt;br /&gt;
Estas macros permiten elegir qué paleta usa un sprite, cargar sus colores y cambiarlos durante el juego.&lt;br /&gt;
&lt;br /&gt;
==== LoadPaletteIDAndAddress ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%LoadPaletteIDAndAddress()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 8 bits: índice de la paleta dentro del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt;: guarda aquí el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; de tu DynamicInfo, con 16 bits, como muestra el ejemplo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: ID de la paleta.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de sus colores en ROM, en formato BGR555.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    STA $0E&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&lt;br /&gt;
    LDA #$01            ; Segunda paleta del DynamicInfo&lt;br /&gt;
    %LoadPaletteIDAndAddress()&lt;br /&gt;
    ; $00-$01 contiene su ID y $02-$04 su dirección ROM.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En PIXI también puede llamarse mediante &amp;lt;code&amp;gt;%DXLoadPaletteIDAndAddress()&amp;lt;/code&amp;gt;, con las mismas entradas y resultados. Esta variante llama a una rutina compartida y después continúa con el código siguiente.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones bajos y guiones, y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignment (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt; asigna y carga una paleta igual que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
Si la paleta ya estaba asignada, mantiene su temporizador de uso en 2 para que no sea reemplazada mientras se utiliza. Si el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; de las opciones está activado, también aplica el efecto global correspondiente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteAssignment(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 utiliza &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; para acceder a las tablas del sprite; 0 permite usar variables independientes del índice del sprite.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable que recibe la paleta asignada. Debe comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Los valores &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt;, ..., &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; corresponden a las paletas 8-F.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteAssignment&amp;lt;/code&amp;gt;: variable o valor con formato &amp;lt;code&amp;gt;--AA----&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; permite que Dynamic Xtreme elija el destino y cargue los colores; &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; utiliza el destino que tú indicas y carga los colores; &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; utiliza ese destino con los colores que ya tiene el nivel.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor con formato &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;. E = 1 permite aplicar el efecto global; E = 0 lo excluye. En modo manual, PPP elige entre la paleta 8 (&amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt;) y la F (&amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt;). En automático, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F. Los cuatro bits bajos no se usan para estas opciones.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteVersion&amp;lt;/code&amp;gt;: 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 &amp;lt;code&amp;gt;!Version,x&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt;: variable que guarda la última versión procesada. Debe comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualIDGroup&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt;: juntos forman el número con el que el sistema reconoce la paleta en los modos manuales. El primero indica el grupo: &amp;lt;code&amp;gt;#$FE&amp;lt;/code&amp;gt; para normal, &amp;lt;code&amp;gt;#$FC&amp;lt;/code&amp;gt; para cluster y &amp;lt;code&amp;gt;#$FD&amp;lt;/code&amp;gt; para extended. El segundo indica el tipo de sprite; en uno normal se utiliza &amp;lt;code&amp;gt;!CustomSpriteNumber,x&amp;lt;/code&amp;gt;, como en el ejemplo.&lt;br /&gt;
&lt;br /&gt;
También puedes crear grupos propios: por ejemplo, usar &amp;lt;code&amp;gt;manualIDGroup = #$FB&amp;lt;/code&amp;gt; para el jugador y &amp;lt;code&amp;gt;#$FA&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt; para distinguir los recursos dentro de cada uno. Los grupos &amp;lt;code&amp;gt;$FE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$FD&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FC&amp;lt;/code&amp;gt; ya son utilizados por las rutinas de sprites normales, extended y cluster, respectivamente.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entrada adicional&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* Si &amp;lt;code&amp;gt;sprite = 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt; debe contener el índice del sprite.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: hay una paleta con la que se puede dibujar; desactivado si todavía no hay ninguna.&lt;br /&gt;
* Guarda el número de paleta en &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt; y actualiza &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt; cuando procesa la versión.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %PaletteAssignment(1, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!NormalPaletteAssignment,x&amp;quot;, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalVersion,x&amp;quot;, &amp;quot;!NormalLastVersion,x&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo utiliza las variables de un sprite normal. &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; que termina la rutina, por lo que no debes añadir código después de ella.&lt;br /&gt;
&lt;br /&gt;
==== PaletteAssignmentNoUpload (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; elige una paleta como &amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt;, pero deja pendiente la carga de sus colores. Permite aplicar después un efecto local y combinarlo con el global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteAssignmentNoUpload(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los parámetros son los mismos que en &amp;lt;code&amp;gt;%PaletteAssignment()&amp;lt;/code&amp;gt;. A recibe el offset de la tabla con 16 bits. &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt; deben comenzar en &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;paletteVersion&amp;lt;/code&amp;gt; elige los colores de la lista del DynamicInfo: 0 para la primera paleta, 1 para la segunda, etc. &amp;lt;code&amp;gt;paletteAssignment&amp;lt;/code&amp;gt; decide el modo: &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; automático, &amp;lt;code&amp;gt;$10&amp;lt;/code&amp;gt; manual y &amp;lt;code&amp;gt;$20&amp;lt;/code&amp;gt; manual sin cargar colores. &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt; utiliza &amp;lt;code&amp;gt;EPPP----&amp;lt;/code&amp;gt;: E permite el efecto global y PPP selecciona la paleta 8-F en manual. En automático, &amp;lt;code&amp;gt;000&amp;lt;/code&amp;gt; permite todas, &amp;lt;code&amp;gt;0XX&amp;lt;/code&amp;gt; distinto de cero permite 8-B y &amp;lt;code&amp;gt;1XX&amp;lt;/code&amp;gt; permite C-F. Para aplicar después un efecto local sobre los colores del DynamicInfo, utiliza el modo automático o manual con carga.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Carry activado: hay una paleta asignada; desactivado si no pudo obtenerse.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: número de la paleta asignada, de dos en dos entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteLastVersion&amp;lt;/code&amp;gt;: última versión procesada.&lt;br /&gt;
* &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt;: ID de la paleta seleccionada del DynamicInfo.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de sus colores.&lt;br /&gt;
* 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.&lt;br /&gt;
* A, X e Y quedan en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
Usa los datos de &amp;lt;code&amp;gt;$00-$04&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
AssignPaletteForEffect:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %PaletteAssignmentNoUpload(1, &amp;quot;!NormalPalette,x&amp;quot;, &amp;quot;!NormalPaletteAssignment,x&amp;quot;, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalVersion,x&amp;quot;, &amp;quot;!NormalLastVersion,x&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Después de llamar a &amp;lt;code&amp;gt;AssignPaletteForEffect&amp;lt;/code&amp;gt; con &amp;lt;code&amp;gt;JSL&amp;lt;/code&amp;gt;, comprueba el carry y aplica el efecto usando los datos devueltos. Conserva Y y &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; para la llamada de concatenación.&lt;br /&gt;
&lt;br /&gt;
La macro ya termina la rutina con &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. El código que aplica el efecto va después de la llamada &amp;lt;code&amp;gt;JSL AssignPaletteForEffect&amp;lt;/code&amp;gt;, no después de la macro dentro de esa rutina.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre usa PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpritePaletteAssignment ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpritePaletteAssignment()&amp;lt;/code&amp;gt; utiliza las variables de paleta del tipo de sprite indicado. Es la macro utilizada por las rutinas PIXI de asignación.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%StandardSpritePaletteAssignment(type, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;quot;Normal&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;Cluster&amp;quot;&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;&amp;quot;Extended&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualIDGroup&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;#$FE&amp;lt;/code&amp;gt; para normal, &amp;lt;code&amp;gt;#$FC&amp;lt;/code&amp;gt; para cluster o &amp;lt;code&amp;gt;#$FD&amp;lt;/code&amp;gt; para extended.&lt;br /&gt;
* También puedes elegir un grupo propio, por ejemplo &amp;lt;code&amp;gt;#$FB&amp;lt;/code&amp;gt; para el jugador o &amp;lt;code&amp;gt;#$FA&amp;lt;/code&amp;gt; para otro tipo de entidad, siempre que esos valores no estén siendo utilizados por otro grupo de tu proyecto.&lt;br /&gt;
* &amp;lt;code&amp;gt;manualID&amp;lt;/code&amp;gt;: variable o valor que identifica el tipo de sprite en los modos manuales.&lt;br /&gt;
* A de 16 bits: el define &amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; del DynamicInfo que contiene las paletas.&lt;br /&gt;
* &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;: índice del sprite.&lt;br /&gt;
* Las variables de Dynamic Xtreme para paleta, opciones, versión y última versión del tipo seleccionado, preparadas como en &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;!PaletteAssignment&amp;lt;/code&amp;gt;: guarda la paleta asignada en la tabla del sprite y devuelve el carry activado cuando se puede dibujar con ella.&lt;br /&gt;
&lt;br /&gt;
La macro ya incluye un &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL PaletteManagement&amp;lt;/code&amp;gt; y no añadas código después de la macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
PaletteManagement:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %StandardSpritePaletteAssignment(&amp;quot;Normal&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt; al eliminar los separadores.&lt;br /&gt;
&lt;br /&gt;
==== StandardSpritePaletteAssignmentNoUpload ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%StandardSpritePaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; utiliza las variables del tipo de sprite seleccionado para asignar la paleta, dejando pendiente la carga de los colores.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%StandardSpritePaletteAssignmentNoUpload(type, manualIDGroup, manualID)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Recibe los mismos parámetros y datos que &amp;lt;code&amp;gt;%StandardSpritePaletteAssignment()&amp;lt;/code&amp;gt;. A debe contener el offset de la tabla de paletas con 16 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El mismo que &amp;lt;code&amp;gt;!PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;: guarda la paleta asignada y devuelve el carry, Y, el ID en &amp;lt;code&amp;gt;$00-$01&amp;lt;/code&amp;gt; y la dirección en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;, con las condiciones indicadas en esa entrada.&lt;br /&gt;
&lt;br /&gt;
La macro ya incluye un &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;. Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL AssignPaletteForEffect&amp;lt;/code&amp;gt;. El código que aplica el efecto va después de esa llamada.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
AssignPaletteForEffect:&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!MySpritePaletteTableOffset&lt;br /&gt;
    %StandardSpritePaletteAssignmentNoUpload(&amp;quot;Normal&amp;quot;, #$FE, &amp;quot;!CustomSpriteNumber,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!MySpritePaletteTableOffset&amp;lt;/code&amp;gt; se genera desde el DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_sprite&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MySprite&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== ReplacePalette (macro general) ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ReplacePalette()&amp;lt;/code&amp;gt; sustituye los colores de una paleta que ya estás usando. Hace lo mismo que &amp;lt;code&amp;gt;!ReplacePalette&amp;lt;/code&amp;gt;, pero tú eliges qué variables leer. Si otros sprites o códigos usan esa misma paleta, también verán los nuevos colores.&lt;br /&gt;
&lt;br /&gt;
Suele utilizarse después de una asignación sin carga, como &amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt;. Primero obtienes la paleta asignada y después preparas en &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt; la dirección de los colores que quieres usar para reemplazarla.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parámetros y entradas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%ReplacePalette(sprite, paletteOption, palette)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 obtiene el índice del sprite desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 0 utiliza variables independientes de ese índice.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor de las opciones de paleta. El bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; indica si se aplica el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable o valor de la paleta de destino, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección ROM de los nuevos colores en BGR555.&lt;br /&gt;
* A en modo de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Resultado&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Llámala cuando cambien los colores que quieres mostrar. Repetir la llamada cada frame obliga a preparar de nuevo la paleta y sus efectos.&lt;br /&gt;
&lt;br /&gt;
Llama a la rutina del ejemplo con &amp;lt;code&amp;gt;JSL ReplaceSpritePalette&amp;lt;/code&amp;gt;. La macro ya incluye el &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt; que termina la rutina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
ReplaceSpritePalette:&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&lt;br /&gt;
    STA $02&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;8&lt;br /&gt;
    STA $03&lt;br /&gt;
    LDA.b #!PaletteMyAlternatePalette&amp;gt;&amp;gt;16&lt;br /&gt;
    STA $04&lt;br /&gt;
    %ReplacePalette(1, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteMyAlternatePalette&amp;lt;/code&amp;gt; es la dirección de una paleta insertada a partir de los recursos del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza eliminando separadores y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_alternate_palette&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyAlternatePalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Efectos de paleta ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 [[es/Dynamic_Xtreme_files_and_formats#Tipos_de_efectos|Tipos de efectos]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;¿Qué llamada necesitas?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Quieres… !! Utiliza…&lt;br /&gt;
|-&lt;br /&gt;
| Teñir una paleta o cambiar su tono, saturación o luminosidad. || &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MixAndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Pasar de una paleta a otra. || &amp;lt;code&amp;gt;PaletteTransition&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Aplicar un efecto que ya definiste en un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt;. || &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DoEffectAndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Darle un efecto propio a un sprite y conservar además el efecto global. || &amp;lt;code&amp;gt;ConcatenateRGBPaletteEffectToGlobal&amp;lt;/code&amp;gt; o su variante HSL, después de asignar la paleta sin carga.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para calcular un efecto directamente, el proceso habitual es preparar los colores originales con &amp;lt;code&amp;gt;SetRGBBase&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;SetHSLBase&amp;lt;/code&amp;gt; y después aplicar el cambio. Los ejemplos utilizan las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt;, que trabajan con las copias de paleta de Dynamic Xtreme y evitan escribir direcciones de memoria.&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;PaletteAssignmentNoUpload&amp;lt;/code&amp;gt;, estas ya se encargan de preparar los colores y completar su carga.&lt;br /&gt;
&lt;br /&gt;
En los ejemplos, prepara A en modo de 8 bits antes de llamar a las macros.&lt;br /&gt;
&lt;br /&gt;
==== Preparar los colores: SetRGBBase y SetHSLBase ====&lt;br /&gt;
&lt;br /&gt;
Antes de modificar los colores, necesitas una copia con la que calcular el efecto. &amp;lt;code&amp;gt;%SetRGBBase()&amp;lt;/code&amp;gt; prepara esa copia para efectos RGB; &amp;lt;code&amp;gt;%SetHSLBase()&amp;lt;/code&amp;gt; la prepara para HSL. Si los colores originales no cambiaron, puedes reutilizarla en los siguientes frames.&lt;br /&gt;
&lt;br /&gt;
En las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; solo indicas el primer color y cuántos colores quieres preparar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%SetRGBBaseDefault(offset, length)&lt;br /&gt;
%SetHSLBaseDefault(offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; es el número del primer color y &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; es la cantidad. Por ejemplo, &amp;lt;code&amp;gt;#$0081&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;#$000F&amp;lt;/code&amp;gt; seleccionan los 15 colores visibles de la paleta 8.&lt;br /&gt;
&lt;br /&gt;
Si necesitas elegir tú las direcciones donde leer y guardar los colores, utiliza las versiones completas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%SetRGBBase(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%SetHSLBase(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;%SetRGBBaseDefault(offset, length)&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%SetHSLBaseDefault(offset, length)&amp;lt;/code&amp;gt; leen de &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteCopy&amp;lt;/code&amp;gt; y guardan el resultado en &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseRGBPalette&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;DX_PPU_CGRAM_BaseHSLPalette&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: preparar una paleta de sprites&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; Paleta 8, sin incluir su primer color transparente.&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
    ; Para trabajar en HSL, utiliza esta variante en su lugar:&lt;br /&gt;
    ; %SetHSLBaseDefault(#$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$81&amp;lt;/code&amp;gt; es el segundo color de la paleta 8: la paleta comienza en el color &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; y se procesan los 15 siguientes.&lt;br /&gt;
&lt;br /&gt;
==== Mezclar colores: Mix y MixAndMerge ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Los parámetros &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; indican el color que quieres alcanzar, entre 0 y 31. Los parámetros &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;#$00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#$7F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Para RGB, los valores 1, 2 y 3 corresponden a rojo, verde y azul. Para HSL corresponden a tono, saturación y luminosidad.&lt;br /&gt;
&lt;br /&gt;
El final del nombre indica qué componentes se modifican:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! RGB !! HSL !! Componentes modificados&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;H&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;L&amp;lt;/code&amp;gt; || Uno.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GB&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SL&amp;lt;/code&amp;gt; || Dos.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RGB&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;HSL&amp;lt;/code&amp;gt; || Los tres.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cada combinación está disponible como &amp;lt;code&amp;gt;Mix...&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MixAndMerge...&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;MixAndMerge...Default&amp;lt;/code&amp;gt;. Por ejemplo: &amp;lt;code&amp;gt;%MixR()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%MixAndMergeR()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%MixAndMergeRDefault()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; omiten las direcciones.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%MixRGB(r1, r2, r3, v1, v2, v3, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%MixAndMergeRG(r1, r2, v1, v2, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%MixAndMergeLDefault(r3, v3, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo RGB: teñir de rojo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; Preparar los colores originales de la paleta 8.&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
    ; Acercar los tres componentes a un rojo puro, aproximadamente a la mitad.&lt;br /&gt;
    %MixAndMergeRGBDefault(#$40, #$40, #$40, #$1F, #$00, #$00, #$0081, #$000F)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los tres primeros valores &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt; indican la intensidad del cambio para rojo, verde y azul. Los siguientes, &amp;lt;code&amp;gt;#$1F, #$00, #$00&amp;lt;/code&amp;gt;, indican el rojo puro al que se acercarán. Los dos últimos seleccionan los 15 colores de la paleta 8.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo HSL: aclarar la paleta&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %SetHSLBaseDefault(#$0081, #$000F)&lt;br /&gt;
    %MixAndMergeLDefault(#$40, #$1F, #$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aquí solo cambia la luminosidad: &amp;lt;code&amp;gt;#$40&amp;lt;/code&amp;gt; aplica aproximadamente la mitad del cambio y &amp;lt;code&amp;gt;#$1F&amp;lt;/code&amp;gt; indica la luminosidad máxima. Este es un ejemplo independiente del anterior.&lt;br /&gt;
&lt;br /&gt;
==== Cambiar entre paletas: PaletteTransition ====&lt;br /&gt;
&lt;br /&gt;
Estas macros acercan cada color de la paleta original al color correspondiente de otra paleta. A diferencia de &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt;, cada color tiene su propio destino. Sirven, por ejemplo, para pasar de los colores normales de un sprite a una paleta de daño.&lt;br /&gt;
&lt;br /&gt;
Las variantes son &amp;lt;code&amp;gt;PaletteTransitionRGB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransitionHSL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransitionRGBAndMerge&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;PaletteTransitionHSLAndMerge&amp;lt;/code&amp;gt;. Las dos variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; también tienen versión &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%PaletteTransitionRGB(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%PaletteTransitionHSLAndMerge(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%PaletteTransitionRGBAndMergeDefault(r1, r2, r3, targetpal, targetpalbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;targetpal&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;targetpalbnk&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: calcular un paso intermedio de una transición&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    ; Este ejemplo trabaja con los primeros 15 colores de la copia de paletas.&lt;br /&gt;
    %SetRGBBaseDefault(#$0000, #$000F)&lt;br /&gt;
    %PaletteTransitionRGBAndMergeDefault(#$40, #$40, #$40, #!PaletteMyTargetRGB, #!PaletteMyTargetRGB&amp;gt;&amp;gt;16, #$0000, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El ejemplo supone que &amp;lt;code&amp;gt;!PaletteMyTargetRGB&amp;lt;/code&amp;gt; corresponde a una paleta de destino RGB generada al instalar un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; de transición. Su dirección queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_target&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyTarget&amp;lt;/code&amp;gt;. Para HSL se utiliza la paleta convertida a HSL y la macro correspondiente.&lt;br /&gt;
&lt;br /&gt;
==== Aplicar un efecto de un archivo: DoEffect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%DoEffect()&amp;lt;/code&amp;gt; aplica un efecto de un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%DoEffect(effect, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%DoEffectAndMerge(effect, src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%DoEffectAndMergeDefaultRGB(effect, offset, length)&lt;br /&gt;
%DoEffectAndMergeDefaultHSL(effect, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;effect&amp;lt;/code&amp;gt;: ID del efecto, como &amp;lt;code&amp;gt;#!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt;.&lt;br /&gt;
* El origen debe contener colores RGB o HSL separados, según el efecto elegido.&lt;br /&gt;
* &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; guarda el resultado con 3 bytes por color para poder seguir modificándolo.&lt;br /&gt;
* &amp;lt;code&amp;gt;DoEffectAndMerge&amp;lt;/code&amp;gt; guarda colores en formato de SNES. Las variantes &amp;lt;code&amp;gt;DefaultRGB&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DefaultHSL&amp;lt;/code&amp;gt; eligen la base correspondiente y escriben en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: aplicar un efecto RGB a la paleta 8&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %SetRGBBaseDefault(#$0081, #$000F)&lt;br /&gt;
    %DoEffectAndMergeDefaultRGB(#!PaletteEffectIDMyEffect0, #$81, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; se genera desde un archivo &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. El número final identifica el efecto dentro del archivo. Si el efecto trabaja en HSL, prepara la base HSL y utiliza &amp;lt;code&amp;gt;%DoEffectAndMergeDefaultHSL()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Convertir entre RGB y HSL ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%RGBToHSL()&amp;lt;/code&amp;gt; convierte colores RGB a HSL y &amp;lt;code&amp;gt;%HSLToRGB()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%RGBToHSL(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
%HSLToRGB(src, srcbnk, dst, dstbnk, offset, length)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: convertir la base RGB a HSL&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %RGBToHSL(#DX_PPU_CGRAM_BaseRGBPalette, #DX_PPU_CGRAM_BaseRGBPalette&amp;gt;&amp;gt;16, #DX_PPU_CGRAM_BaseHSLPalette, #DX_PPU_CGRAM_BaseHSLPalette&amp;gt;&amp;gt;16, #$0081, #$000F)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Combinar un efecto propio con el global ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%ConcatenateRGBPaletteEffectToGlobal()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;%ConcatenateHSLPaletteEffectToGlobal()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Suelen utilizarse después de &amp;lt;code&amp;gt;%PaletteAssignmentNoUpload()&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
%ConcatenateRGBPaletteEffectToGlobal(sprite, paletteOption, palette)&lt;br /&gt;
%ConcatenateHSLPaletteEffectToGlobal(sprite, paletteOption, palette)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sprite&amp;lt;/code&amp;gt;: 1 recupera el índice del sprite desde &amp;lt;code&amp;gt;!SpriteIndex&amp;lt;/code&amp;gt;; 0 permite utilizar variables propias.&lt;br /&gt;
* &amp;lt;code&amp;gt;paletteOption&amp;lt;/code&amp;gt;: variable o valor de las opciones de paleta; activa el bit &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt; para incluir el efecto global.&lt;br /&gt;
* &amp;lt;code&amp;gt;palette&amp;lt;/code&amp;gt;: variable que contiene la paleta asignada, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$0E&amp;lt;/code&amp;gt; de dos en dos.&lt;br /&gt;
* A de 16 bits: ID del efecto local RGB o HSL, según la macro.&lt;br /&gt;
* X de 8 bits: copia del valor de la paleta asignada.&lt;br /&gt;
* Y de 8 bits: conserva el valor devuelto por la asignación sin carga.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02-$04&amp;lt;/code&amp;gt;: dirección de los colores originales preparada por esa asignación.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;RTL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: completar una asignación sin carga&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
; Llamar esta rutina con JSL después de asignar la paleta sin carga.&lt;br /&gt;
; Deben conservarse Y y $02-$04 de aquella llamada.&lt;br /&gt;
ApplyLocalEffect:&lt;br /&gt;
    LDA !NormalPalette,x&lt;br /&gt;
    TAX&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA #!PaletteEffectIDMyEffect0&lt;br /&gt;
    %ConcatenateRGBPaletteEffectToGlobal(1, &amp;quot;!NormalPaletteOption,x&amp;quot;, &amp;quot;!NormalPalette,x&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!PaletteEffectIDMyEffect0&amp;lt;/code&amp;gt; se genera desde un &amp;lt;code&amp;gt;*.paleffect&amp;lt;/code&amp;gt; y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza en PascalCase eliminando separadores: &amp;lt;code&amp;gt;my_effect&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyEffect&amp;lt;/code&amp;gt;. Para un efecto HSL, utiliza la macro HSL. Si usas Y para leer una tabla de efectos, guarda su valor con &amp;lt;code&amp;gt;PHY&amp;lt;/code&amp;gt; y recupéralo con &amp;lt;code&amp;gt;PLY&amp;lt;/code&amp;gt; antes de concatenar.&lt;br /&gt;
&lt;br /&gt;
==== Elegir las direcciones y combinar varios efectos ====&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;Default&amp;lt;/code&amp;gt; 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:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;src&amp;lt;/code&amp;gt;: dónde leer los colores originales; &amp;lt;code&amp;gt;srcbnk&amp;lt;/code&amp;gt;: su banco.&lt;br /&gt;
* &amp;lt;code&amp;gt;dst&amp;lt;/code&amp;gt;: dónde guardar el resultado; &amp;lt;code&amp;gt;dstbnk&amp;lt;/code&amp;gt;: su banco. El destino debe ser un espacio de RAM que tu código pueda utilizar.&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;: primer color que se procesará, contando desde 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt;: cantidad de colores que se procesarán.&lt;br /&gt;
&lt;br /&gt;
Para indicar una dirección fija, se utiliza &amp;lt;code&amp;gt;#Nombre&amp;lt;/code&amp;gt; para la dirección y &amp;lt;code&amp;gt;#Nombre&amp;gt;&amp;gt;16&amp;lt;/code&amp;gt; para su banco, como en el ejemplo de conversión RGB a HSL. También puedes pasar variables que contengan esos datos.&lt;br /&gt;
&lt;br /&gt;
El espacio necesario depende del paso que estés realizando:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Operación !! Lee !! Guarda&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SetRGBBase&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SetHSLBase&amp;lt;/code&amp;gt; || Paleta normal: 2 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Mix&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PaletteTransition&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DoEffect&amp;lt;/code&amp;gt; sin &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| Variantes &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Paleta normal: 2 bytes por color.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RGBToHSL&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;HSLToRGB&amp;lt;/code&amp;gt; || Colores separados: 3 bytes por color. || Colores separados: 3 bytes por color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si quieres aplicar dos efectos seguidos, el primero debe guardar sus colores separados, sin &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt;. El segundo lee ese resultado y utiliza &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt; para dejar la paleta lista para cargarla. Si uno trabaja en RGB y el otro en HSL, convierte los colores entre ambos pasos.&lt;br /&gt;
&lt;br /&gt;
Las macros utilizan memoria temporal, entre otras las direcciones &amp;lt;code&amp;gt;$45-$50&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$51-$53&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$6A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8C&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$8E&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$0E-$0F&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$D5-$D7&amp;lt;/code&amp;gt;, según la operación. No guardes en ellas datos que necesites conservar después de la llamada.&lt;br /&gt;
&lt;br /&gt;
=== PPU ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qué llamada elegir&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Necesitas… !! VRAM !! CGRAM&lt;br /&gt;
|-&lt;br /&gt;
| Indicar la dirección de origen y su banco por separado. || &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Indicar una dirección completa y dejar que la macro obtenga el banco. || &amp;lt;code&amp;gt;TransferToVRAMFromAddr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferToCGRAMFromAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Cargar un recurso completo registrado en Dynamic Xtreme. || &amp;lt;code&amp;gt;TransferResourceToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferResourceToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Cargar solo una cantidad de bytes de un recurso. || &amp;lt;code&amp;gt;TransferResourceToVRAMWithLenght&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;TransferResourceToCGRAMWithLenght&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Las versiones normales comprueban si la transferencia cabe dentro del límite de bytes del frame:&lt;br /&gt;
&lt;br /&gt;
* Carry activado: la transferencia quedó programada.&lt;br /&gt;
* Carry desactivado: no se programó porque superaría ese límite. Tu código puede intentarlo en otro frame.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== TransferToVRAM ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToVRAM()&amp;lt;/code&amp;gt; programa una copia de gráficos desde ROM o RAM hacia VRAM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToVRAM(VRAMOffset, ResourceAddr, ResourceBNK, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;VRAMOffset&amp;lt;/code&amp;gt;: dirección de destino en VRAM, expresada en palabras de 2 bytes. Por ejemplo, copiar &amp;lt;code&amp;gt;$0200&amp;lt;/code&amp;gt; bytes desde &amp;lt;code&amp;gt;$6000&amp;lt;/code&amp;gt; ocupa las palabras &amp;lt;code&amp;gt;$6000-$60FF&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;ResourceAddr&amp;lt;/code&amp;gt;: dirección de origen dentro de su banco.&lt;br /&gt;
* &amp;lt;code&amp;gt;ResourceBNK&amp;lt;/code&amp;gt;: banco del origen.&lt;br /&gt;
* &amp;lt;code&amp;gt;Lenght&amp;lt;/code&amp;gt;: cantidad de bytes que se copiarán. Se conserva esta escritura del nombre porque así aparece en la macro.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: programar la carga de gráficos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToVRAM(#$6000, #!ResourceMyGraphics, #!ResourceMyGraphics&amp;gt;&amp;gt;16, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
    ; La copia se realizará en el próximo NMI.&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; es la dirección de un recurso registrado desde un DynamicInfo; queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. El nombre se normaliza eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;. La cantidad de bytes solicitada debe existir en ese recurso.&lt;br /&gt;
&lt;br /&gt;
==== TransferToVRAMFromAddr ====&lt;br /&gt;
&lt;br /&gt;
Hace la misma copia, pero recibe la dirección completa del origen. La macro separa su dirección y banco por ti.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToVRAMFromAddr(VRAMOffset, addr, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; se escribe sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;; los otros parámetros se entregan como en &amp;lt;code&amp;gt;TransferToVRAM&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferToVRAMFromAddr(#$6000, !ResourceMyGraphics, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; se genera desde un recurso del DynamicInfo y queda en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;. Su nombre se normaliza en PascalCase: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; se convierte en &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== TransferResourceToVRAM y TransferResourceToVRAMWithLenght ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferResourceToVRAM(VRAMOffset, ResourceName)&lt;br /&gt;
%TransferResourceToVRAMWithLenght(VRAMOffset, ResourceName, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para un recurso cuyos defines sean &amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceMyGraphicsSize&amp;lt;/code&amp;gt;, escribe &amp;lt;code&amp;gt;&amp;quot;MyGraphics&amp;quot;&amp;lt;/code&amp;gt; como &amp;lt;code&amp;gt;ResourceName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: cargar el recurso completo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToVRAM(#$6000, &amp;quot;MyGraphics&amp;quot;)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: cargar solo sus primeros $0200 bytes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToVRAMWithLenght(#$6000, &amp;quot;MyGraphics&amp;quot;, #$0200)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
El nombre y el tamaño se obtienen de los defines generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; al instalar los recursos del DynamicInfo. Utiliza el nombre normalizado: &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;, eliminando los separadores y poniendo en mayúscula la inicial de cada palabra.&lt;br /&gt;
&lt;br /&gt;
==== TransferToCGRAM ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;%TransferToCGRAM()&amp;lt;/code&amp;gt; programa una copia de colores desde ROM o RAM hacia una paleta de SNES.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToCGRAM(CGRAMOffset, TableAddr, TableBNK, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;CGRAMOffset&amp;lt;/code&amp;gt;: número del primer color de destino, entre &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;$FF&amp;lt;/code&amp;gt;. Por ejemplo, la paleta 8 comienza en el color &amp;lt;code&amp;gt;$80&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;TableAddr&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;TableBNK&amp;lt;/code&amp;gt;: dirección y banco de los colores que se van a copiar.&lt;br /&gt;
* &amp;lt;code&amp;gt;Lenght&amp;lt;/code&amp;gt;: cantidad de bytes. Cada color ocupa 2 bytes; 15 colores ocupan &amp;lt;code&amp;gt;$001E&amp;lt;/code&amp;gt; bytes.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;AndMerge&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar los 15 colores visibles de la paleta 8&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToCGRAM(#$81, #DX_PPU_CGRAM_PaletteWriteMirror+$0102, #DX_PPU_CGRAM_PaletteWriteMirror&amp;gt;&amp;gt;16, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Este ejemplo toma el resultado de un efecto guardado en &amp;lt;code&amp;gt;DX_PPU_CGRAM_PaletteWriteMirror&amp;lt;/code&amp;gt;. El desplazamiento &amp;lt;code&amp;gt;$0102&amp;lt;/code&amp;gt; corresponde al color &amp;lt;code&amp;gt;$81&amp;lt;/code&amp;gt;, porque cada color ocupa 2 bytes. Se omite el primer color de la paleta, que es transparente en sprites.&lt;br /&gt;
&lt;br /&gt;
==== TransferToCGRAMFromAddr ====&lt;br /&gt;
&lt;br /&gt;
Hace la misma copia de colores, pero recibe la dirección completa del origen. Escribe &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; sin &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferToCGRAMFromAddr(CGRAMOffset, addr, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap; overflow-wrap: anywhere;&amp;quot;&amp;gt;&lt;br /&gt;
    %TransferToCGRAMFromAddr(#$81, DX_PPU_CGRAM_PaletteWriteMirror+$0102, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== TransferResourceToCGRAM y TransferResourceToCGRAMWithLenght ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%TransferResourceToCGRAM(CGRAMOffset, ResourceName)&lt;br /&gt;
%TransferResourceToCGRAMWithLenght(CGRAMOffset, ResourceName, Lenght)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar un recurso completo de colores&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToCGRAM(#$80, &amp;quot;MyColors&amp;quot;)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: copiar solo 15 colores&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %TransferResourceToCGRAMWithLenght(#$81, &amp;quot;MyColors&amp;quot;, #$001E)&lt;br /&gt;
    BCC .NotLoaded&lt;br /&gt;
.NotLoaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Estos ejemplos suponen un recurso general de colores con los defines &amp;lt;code&amp;gt;!ResourceMyColors&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;!ResourceMyColorsSize&amp;lt;/code&amp;gt;, generados en &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt; desde un DynamicInfo. Utiliza el nombre normalizado: &amp;lt;code&amp;gt;my_colors&amp;lt;/code&amp;gt; pasa a &amp;lt;code&amp;gt;MyColors&amp;lt;/code&amp;gt;. En el segundo ejemplo, el recurso debe comenzar con los 15 colores que se quieren copiar, sin anteponer el color transparente.&lt;br /&gt;
&lt;br /&gt;
==== Variantes Forced ====&lt;br /&gt;
&lt;br /&gt;
Todas las transferencias anteriores tienen una variante cuyo nombre comienza con &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;. Programa la copia aunque supere el límite de bytes del frame. La cantidad copiada también se suma al total de ese frame.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! VRAM !! CGRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferToVRAMFromAddr&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferToCGRAMFromAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferResourceToVRAM&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferResourceToCGRAM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ForcedTransferResourceToVRAMWithLenght&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ForcedTransferResourceToCGRAMWithLenght&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Reciben los mismos parámetros que las versiones sin &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %ForcedTransferResourceToVRAM(#$6000, &amp;quot;MyGraphics&amp;quot;)&lt;br /&gt;
    ; No se comprueba el carry en esta variante.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt; corresponde al recurso &amp;lt;code&amp;gt;!ResourceMyGraphics&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;DXDefines.asm&amp;lt;/code&amp;gt;, generado desde el DynamicInfo. Se utiliza el nombre normalizado, como &amp;lt;code&amp;gt;my_graphics&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MyGraphics&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Utiliza &amp;lt;code&amp;gt;Forced&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Matemáticas ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Prepara A en modo de 8 bits antes de llamarlas. Las macros no cambian por ti el tamaño de A, X o Y.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cómo escribir los argumentos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Mul&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Div&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MulAfterMul&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DivAfterDiv&amp;lt;/code&amp;gt; pegan el argumento directamente después de &amp;lt;code&amp;gt;LDA&amp;lt;/code&amp;gt;. Escribe el argumento entre comillas con un espacio al principio: &amp;lt;code&amp;gt;&amp;quot; #$05&amp;quot;&amp;lt;/code&amp;gt; produce &amp;lt;code&amp;gt;LDA #$05&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
También puedes comenzar el argumento con &amp;lt;code&amp;gt;.b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;.l&amp;lt;/code&amp;gt; para elegir cómo se escribe el acceso a memoria. Por ejemplo, si &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; contiene el número que quieres multiplicar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot;.b $02&amp;quot;, &amp;quot; #$07&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Esto genera &amp;lt;code&amp;gt;LDA.b $02&amp;lt;/code&amp;gt; para leer el primer número y &amp;lt;code&amp;gt;LDA #$07&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Las variantes con &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt;, además de &amp;lt;code&amp;gt;MulAfterDiv&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;DivAfterMul&amp;lt;/code&amp;gt;, ya añaden un espacio antes de los argumentos. En ellas puedes escribir los valores normalmente, como &amp;lt;code&amp;gt;%MulW(#$05, #$07)&amp;lt;/code&amp;gt;. En la implementación actual no se pasan los sufijos &amp;lt;code&amp;gt;.b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;.l&amp;lt;/code&amp;gt; de esta misma manera a esas variantes, porque el espacio que añaden quedaría entre &amp;lt;code&amp;gt;LDA&amp;lt;/code&amp;gt; y el sufijo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;¿Qué significa la W?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
El hardware necesita un pequeño tiempo para terminar el cálculo. Las macros con &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; incluyen esa espera: puedes leer el resultado inmediatamente después. Las versiones sin &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;W&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Los resultados se leen mediante estos defines:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;!MultiplicationResult&amp;lt;/code&amp;gt;: resultado de multiplicar, de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;!DivisionResult&amp;lt;/code&amp;gt;: cociente de la división, de 16 bits.&lt;br /&gt;
* &amp;lt;code&amp;gt;!RemainderResult&amp;lt;/code&amp;gt;: resto de la división, de 16 bits.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Mul y MulW ====&lt;br /&gt;
&lt;br /&gt;
Multiplican dos valores de 8 bits y producen un resultado de 16 bits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Mul(a, b)&lt;br /&gt;
%MulW(a, b)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; pueden ser valores inmediatos, como &amp;lt;code&amp;gt;#$06&amp;lt;/code&amp;gt;, o variables de 8 bits.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: 6 × 7 = 42&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %MulW(#$06, #$07)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $002A, es decir, 42&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La llamada sin espera sería &amp;lt;code&amp;gt;%Mul(&amp;quot; #$06&amp;quot;, &amp;quot; #$07&amp;quot;)&amp;lt;/code&amp;gt;. En ese caso no leas el resultado inmediatamente: ejecuta antes otro código que no utilice el hardware de multiplicación o división.&lt;br /&gt;
&lt;br /&gt;
==== Div y DivW ====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%Div(ah, al, b)&lt;br /&gt;
%DivW(ah, al, b)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;ah&amp;lt;/code&amp;gt;: byte alto del número que quieres dividir.&lt;br /&gt;
* &amp;lt;code&amp;gt;al&amp;lt;/code&amp;gt;: byte bajo del mismo número.&lt;br /&gt;
* &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;: número por el que divides, entre 1 y 255.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: 300 ÷ 7 = 42, con resto 6&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ; 300 = $012C: byte alto $01, byte bajo $2C.&lt;br /&gt;
    %DivW(#$01, #$2C, #$07)&lt;br /&gt;
&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $002A, es decir, 42&lt;br /&gt;
    LDA !RemainderResult         ; A = $0006&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
También puedes pasar una variable de 16 bits como dos argumentos: &amp;lt;code&amp;gt;%DivW(MiNumero+1, MiNumero, #$07)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;MiNumero&amp;lt;/code&amp;gt; representa aquí una variable definida por tu código.&lt;br /&gt;
&lt;br /&gt;
==== Continuar desde el resultado anterior ====&lt;br /&gt;
&lt;br /&gt;
Las variantes &amp;lt;code&amp;gt;AfterMul&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;AfterDiv&amp;lt;/code&amp;gt; toman el resultado del cálculo anterior como primer número. Solo debes indicar el segundo número.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Macro !! Cálculo que realiza&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MulAfterMul(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MulWAfterMul(b)&amp;lt;/code&amp;gt; || Toma los 8 bits bajos del resultado de la multiplicación anterior y los multiplica por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MulAfterDiv(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MulWAfterDiv(b)&amp;lt;/code&amp;gt; || Toma los 8 bits bajos del cociente anterior y los multiplica por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DivAfterMul(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DivWAfterMul(b)&amp;lt;/code&amp;gt; || Divide el resultado completo de la multiplicación anterior por b.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DivAfterDiv(b)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;DivWAfterDiv(b)&amp;lt;/code&amp;gt; || Divide el cociente completo de la división anterior por b.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
La W sigue indicando que puedes leer el nuevo resultado inmediatamente después. Las variantes &amp;lt;code&amp;gt;After...&amp;lt;/code&amp;gt; ya incluyen la espera que necesitan para tomar el resultado del cálculo anterior.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dos multiplicaciones, (6 × 7) × 2 = 84&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot; #$06&amp;quot;, &amp;quot; #$07&amp;quot;)&lt;br /&gt;
    %MulWAfterMul(#$02)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $0054, es decir, 84&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dividir y después multiplicar, (100 ÷ 4) × 3 = 75&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Div(&amp;quot; #$00&amp;quot;, &amp;quot; #$64&amp;quot;, &amp;quot; #$04&amp;quot;)&lt;br /&gt;
    %MulWAfterDiv(#$03)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !MultiplicationResult    ; A = $004B, es decir, 75&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: multiplicar y después dividir, (20 × 15) ÷ 4 = 75&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Mul(&amp;quot; #$14&amp;quot;, &amp;quot; #$0F&amp;quot;)&lt;br /&gt;
    %DivWAfterMul(#$04)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $004B, es decir, 75&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ejemplo: dos divisiones, (300 ÷ 3) ÷ 4 = 25&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    %Div(&amp;quot; #$01&amp;quot;, &amp;quot; #$2C&amp;quot;, &amp;quot; #$03&amp;quot;)&lt;br /&gt;
    %DivWAfterDiv(#$04)&lt;br /&gt;
    REP #$20&lt;br /&gt;
    LDA !DivisionResult          ; A = $0019, es decir, 25&lt;br /&gt;
    SEP #$20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En las multiplicaciones, el primer número siempre se limita a 8 bits. Si el resultado anterior era mayor que 255, &amp;lt;code&amp;gt;MulAfterMul&amp;lt;/code&amp;gt; o &amp;lt;code&amp;gt;MulAfterDiv&amp;lt;/code&amp;gt; solo utilizará su byte bajo. Las divisiones de esta tabla sí toman el resultado anterior completo, de 16 bits.&lt;/div&gt;</summary>
		<author><name>Anonimzwx</name></author>
	</entry>
</feed>