Bueno, no sé si solo es a mi, pero es una cosa que siempre me ha molestado muchísimo del DNS. Cada vez que haces un warp, cuando lanzas una pokeball, cuando usas ciertos ataques (absorber, destello...)... la pantalla 'parpadea', y durante un frame muestra la pantalla o parte de esta con los colores sin filtrar (no aplica el filtro de colores DNS).
Ayer me dio por mirarlo en un minuto que tuve libre, y bueno, encontré el problema y lo he solucionado. Solo diré que me cago en Game Freak.
En fin, espero no ser el único ido de la cabeza al que le molestaba esto y que le sirva a alguien más.
PD: No arregla el parpadeo solo en los warp, lo arregla en general, pero pensé que el título era mejor así(?).
Ayer me dio por mirarlo en un minuto que tuve libre, y bueno, encontré el problema y lo he solucionado. Solo diré que me cago en Game Freak.
- Esmeralda: Ir a '080A1BC6'.
- Fire Red: Ir a '0807067A'.
- Ruby: Ir a '08073CE6'.
En esa dirección pegamos lo siguiente:
Bienvenidos a un nuevo mundo, uno en el que el DNS funciona bien.
- Fire Red: Ir a '0807067A'.
- Ruby: Ir a '08073CE6'.
En esa dirección pegamos lo siguiente:
Código:
00 00 00 00 00 00 00 00 FF F7 F7 FE
Este apartado es más que nada para aquel al que le interese qué es lo que pasaba y qué es lo que he hecho.
Antes de nada explicar brevemente como funciona el DNS. En los juegos de pokemon de gba, hay una función (llamada TransferPlttBuffer en pret) que se encarga de transferir la información del Buffer de paletas a la RAM de paletas, encargándose del DMA transfer. Es decir, la RAM de paletas es escrita desde esta función.
La rutina DNS lo que hace es incrustarse en esta función 'TransferPlttBuffer', para ejecutarse cada vez que una función del ROM llame a la función. De esta manera, cada vez que las paletas se vayan a 'refrescar', la rutina DNS se encargará de refrescarlas modificando los colores según los filtros que correspondan a la hora.
Sin embargo, por algún motivo y solo durante un frame, la RAM de paletas se estaba actualizando sin pasar por los filtros de DNS (dando lugar al efecto del flashazo/parpadeo). Es decir, algún puto gañan estaba haciendo la transferencia del buffer de paletas a la RAM sin llamar a 'TransferPlttBuffer'. Ahora solo quedaba lo divertido, buscar que estaba haciendo el CpuSet.
Mirando un poco en el debugger lo encontré, y también estaba en pret. Ahí estaba, en la función 'BeginNormalPaletteFade' había un precioso CpuSet pasando los bytes del Buffer a la RAM de paletas sin llamar al TransferPlttBuffer e ignorando mi DNS.
La solución es bastante simple, me cargo el CpuSet chustero que hicieron y lo sustituyo por una llamada (bl) a la función 'TransferPlttBuffer'. Como la posición relativa es igual en todos los ROM, el bl es el mismo (mismo HEX para los 3 ROM).
Antes de nada explicar brevemente como funciona el DNS. En los juegos de pokemon de gba, hay una función (llamada TransferPlttBuffer en pret) que se encarga de transferir la información del Buffer de paletas a la RAM de paletas, encargándose del DMA transfer. Es decir, la RAM de paletas es escrita desde esta función.
Código:
void TransferPlttBuffer(void)
{
if (!gPaletteFade.bufferTransferDisabled)
{
void *src = gPlttBufferFaded;
void *dest = (void *)PLTT;
DmaCopy16(3, src, dest, PLTT_SIZE);
sPlttBufferTransferPending = 0;
if (gPaletteFade.mode == HARDWARE_FADE && gPaletteFade.active)
UpdateBlendRegisters();
}
}
Sin embargo, por algún motivo y solo durante un frame, la RAM de paletas se estaba actualizando sin pasar por los filtros de DNS (dando lugar al efecto del flashazo/parpadeo). Es decir, algún puto gañan estaba haciendo la transferencia del buffer de paletas a la RAM sin llamar a 'TransferPlttBuffer'. Ahora solo quedaba lo divertido, buscar que estaba haciendo el CpuSet.
Mirando un poco en el debugger lo encontré, y también estaba en pret. Ahí estaba, en la función 'BeginNormalPaletteFade' había un precioso CpuSet pasando los bytes del Buffer a la RAM de paletas sin llamar al TransferPlttBuffer e ignorando mi DNS.
Código:
bool8 BeginNormalPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targetY, u16 blendColor)
{
u8 temp;
register u32 _blendColor asm("r8") = blendColor;
if (gPaletteFade.active)
{
return FALSE;
}
else
{
gPaletteFade.deltaY = 2;
if (delay < 0)
{
gPaletteFade.deltaY += (delay * -1);
delay = 0;
}
gPaletteFade_selectedPalettes = selectedPalettes;
gPaletteFade.delayCounter = delay;
gPaletteFade_delay = delay;
gPaletteFade.y = startY;
gPaletteFade.targetY = targetY;
gPaletteFade.blendColor = _blendColor;
gPaletteFade.active = 1;
gPaletteFade.mode = NORMAL_FADE;
if (startY < targetY)
gPaletteFade.yDec = 0;
else
gPaletteFade.yDec = 1;
UpdatePaletteFade();
temp = gPaletteFade.bufferTransferDisabled;
gPaletteFade.bufferTransferDisabled = 0;
[B]CpuCopy32(gPlttBufferFaded, (void *)PLTT, PLTT_SIZE);[/B] // En Corea del Norte ejecutan por menos
sPlttBufferTransferPending = 0;
if (gPaletteFade.mode == HARDWARE_FADE && gPaletteFade.active)
UpdateBlendRegisters();
gPaletteFade.bufferTransferDisabled = temp;
return TRUE;
}
}
Es bastante fácil, solo tienes que modificar la función 'BeginNormalPaletteFade' en src/palettes.c:
Código:
bool8 BeginNormalPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targetY, u16 blendColor)
{
u8 temp;
register u32 _blendColor asm("r8") = blendColor;
if (gPaletteFade.active)
{
return FALSE;
}
else
{
gPaletteFade.deltaY = 2;
if (delay < 0)
{
gPaletteFade.deltaY += (delay * -1);
delay = 0;
}
gPaletteFade_selectedPalettes = selectedPalettes;
gPaletteFade.delayCounter = delay;
gPaletteFade_delay = delay;
gPaletteFade.y = startY;
gPaletteFade.targetY = targetY;
gPaletteFade.blendColor = _blendColor;
gPaletteFade.active = 1;
gPaletteFade.mode = NORMAL_FADE;
if (startY < targetY)
gPaletteFade.yDec = 0;
else
gPaletteFade.yDec = 1;
UpdatePaletteFade();
temp = gPaletteFade.bufferTransferDisabled;
gPaletteFade.bufferTransferDisabled = 0;
[S][B]CpuCopy32(gPlttBufferFaded, (void *)PLTT, PLTT_SIZE);[/B] [/S]//Esta línea fuera
[B][I] TransferPlttBuffer();[/I][/B] //Esta línea dentro
sPlttBufferTransferPending = 0;
if (gPaletteFade.mode == HARDWARE_FADE && gPaletteFade.active)
UpdateBlendRegisters();
gPaletteFade.bufferTransferDisabled = temp;
return TRUE;
}
}
En fin, espero no ser el único ido de la cabeza al que le molestaba esto y que le sirva a alguien más.
PD: No arregla el parpadeo solo en los warp, lo arregla en general, pero pensé que el título era mejor así(?).
Última edición: