Existen dos funciones que controlan la animación frontal del Pokemon: "
PokemonSummaryDoMonAnimation" y "
DoMonFrontSpriteAnimation". "
PokemonSummaryDoMonAnimation" controla la animación en el menú principal mientras que "
DoMonFrontSpriteAnimation" controla la animación en el resto de eventos del juego donde se muestra el frontal del Pokemon como puede ser el combate, la escena de evolución del Pokemon, de apertura de un huevo, el hall de la fama, etc.
La función "
PokemonSummaryDoMonAnimation" está presente en el archivo:
pokemon_summary_screen.c
La función "
DoMonFrontSpriteAnimation" está presente en los archivos:
contest_util.c,
egg_hatch.c,
evolution_scene.c,
hall_of_fame.c, etc.
Amabas funciones están presentes en el archivo
pokemon.c donde se encuentra el código principal, que es diferente para cada una.
Es debido a esta diferencia que el loop funciona perfectamente en el menú Pokemon pero no en los combates ni en el resto de escenas, ya que en estos casos el juego se queda esperando a que termine la animación para avanzar. Por tanto se deduce que para la función "
DoMonFrontSpriteAnimation" hay algo en el código que le indica que espere mientras que en "
PokemonSummaryDoMonAnimation" no.
En el caso de la escena de evolución existe una función específica llamada "
EvoScene_DoMonAnimation" que controla la función "
DoMonFrontSpriteAnimation" y otra dependiente de esta llamada "
EvoScene_IsMonAnimFinished" que le dice al juego si ha finalizado la animación.
Si observamos los códigos de estas dos funciones vemos lo siguiente:
Código:
static void EvoScene_DoMonAnimation(u8 monSpriteId, u16 speciesId)
{
DoMonFrontSpriteAnimation(&gSprites[monSpriteId], speciesId, FALSE, 0);
}
static bool32 EvoScene_IsMonAnimFinished(u8 monSpriteId)
{
if (gSprites[monSpriteId].callback == SpriteCallbackDummy)
return TRUE;
return FALSE;
}
En "EvoScene_IsMonAnimFinished" indica que si el Pokemon deja de moverse (== SpriteCallbackDummy/TRUE) la animación ha finalizado y si aun no ha dejado de moverse (== SpriteCallbackDummy/FALSE) la animación no ha finalizado y la escena de evolución no puede continuar. Dando como resultado lo siguiente:
Por ello he modificado el código de la siguiente manera:
Código:
static bool32 EvoScene_IsMonAnimFinished(u8 monSpriteId)
{
if (gSprites[monSpriteId].callback == SpriteCallbackDummy)
return TRUE;
return TRUE;
}
De esta forma se "engaña" al juego para que continue ya que en ambos casos el código indica que la animación ha finalizado, aunque en la realidad no es así ya que tiene aplicado el loop. Y el resultado es este:
Conseguido! Funciona perfectamente.
Ahora viene el problema, se podría suponer que existe una función así para el combate y para las otras escenas pero no es así, o al menos no están tan claras o no las encuentro. Volviendo al tema principal, la animación en combate estoy casi seguro de que la clave son estas tres funciones:
"
SpriteCb_WildMonAnimate" en
battle_main.c:
Código:
static void SpriteCb_WildMonAnimate(struct Sprite *sprite)
{
if (!gPaletteFade.active)
{
BattleAnimateFrontSprite(sprite, sprite->sSpeciesId, FALSE, 1);
}
}
"
BattleAnimateFrontSprite" en
pokemon.c:
Código:
void BattleAnimateFrontSprite(struct Sprite* sprite, u16 species, bool8 noCry, u8 arg3)
{
if (gHitMarker & HITMARKER_NO_ANIMATIONS && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK)))
DoMonFrontSpriteAnimation(sprite, species, noCry, arg3 | 0x80);
else
DoMonFrontSpriteAnimation(sprite, species, noCry, arg3);
}
Y "
DoMonFrontSpriteAnimation" en
pokemon.c:
Código:
void DoMonFrontSpriteAnimation(struct Sprite* sprite, u16 species, bool8 noCry, u8 arg3)
{
s8 pan;
switch (arg3 & 0x7F)
{
case 0:
pan = -25;
break;
case 1:
pan = 25;
break;
default:
pan = 0;
break;
}
if (arg3 & 0x80)
{
if (!noCry)
PlayCry1(species, pan);
sprite->callback = SpriteCallbackDummy;
}
else
{
if (!noCry)
{
PlayCry1(species, pan);
if (HasTwoFramesAnimation(species))
StartSpriteAnim(sprite, 1);
}
if (sMonAnimationDelayTable[species - 1] != 0)
{
u8 taskId = CreateTask(Task_AnimateAfterDelay, 0);
STORE_PTR_IN_TASK(sprite, taskId, 0);
gTasks[taskId].data[2] = sMonFrontAnimIdsTable[species - 1];
gTasks[taskId].data[3] = sMonAnimationDelayTable[species - 1];
}
else
{
LaunchAnimationTaskForFrontSprite(sprite, sMonFrontAnimIdsTable[species - 1]);
}
sprite->callback = SpriteCallbackDummy_2;
}
}
Como podéis ver una controla a la otra de tal manera:
"
SpriteCb_WildMonAnimate"->"
BattleAnimateFrontSprite"->"
DoMonFrontSpriteAnimation". He probado a modificar alguna cosa como el "FALSE, 1" en "
SpriteCb_WildMonAnimate" pero no consigo nada. Creo que estoy cerca de dar con la tecla pero al depender de varias funciones como sospecho no soy capaz de deducir que cambiar. Dejo este tocho aquí por si a alguien con más conocimiento se le ocurre algo.