- 23
- Posts
- 6
- Years
- Seen Nov 28, 2023
Hi all!
I am trying to add a feature where an animation is shown when a pokemon enters battle, similarly to the shiny animation. For demo purposes, the condition for this animation triggering is that the mon's species is Treecko. However, I've encountered a problem as the game is softlocked after showing the animation, so my guess is that some sort of return statement or callbacks should be involved, but I'm not skilled enough in C to debug this myself. Any help in making the battle resume normally after the animation would be immensely appreciated!
Background: I am using RHH's pokeemerald-expansion version 1.6.1.
The animation I've been using is the one for Harden and Iron defense from src/battle_anim_dark.c. I've copied and renamed the functions AnimTask_MetallicShine and AnimTask_MetallicShine_Step. I've inserted them into src/battle_anim_throw.c, where the important function TryShinyAnimation is.
Changes in src/battle_anim_throw.c:
added in the very beginning of the file:
added where functions are declared:
changes in the function TryShinyAnimation:
inserted between functions SpriteCB_ShinyStars_Encircle and AnimTask_LoadPokeblockGfx:
I am trying to add a feature where an animation is shown when a pokemon enters battle, similarly to the shiny animation. For demo purposes, the condition for this animation triggering is that the mon's species is Treecko. However, I've encountered a problem as the game is softlocked after showing the animation, so my guess is that some sort of return statement or callbacks should be involved, but I'm not skilled enough in C to debug this myself. Any help in making the battle resume normally after the animation would be immensely appreciated!
Background: I am using RHH's pokeemerald-expansion version 1.6.1.
The animation I've been using is the one for Harden and Iron defense from src/battle_anim_dark.c. I've copied and renamed the functions AnimTask_MetallicShine and AnimTask_MetallicShine_Step. I've inserted them into src/battle_anim_throw.c, where the important function TryShinyAnimation is.
Changes in src/battle_anim_throw.c:
added in the very beginning of the file:
Code:
#include "contest.h"
added where functions are declared:
Code:
static void AnimTask_MetallicShineCopy(u8);
static void AnimTask_MetallicShine_StepCopy(u8);
changes in the function TryShinyAnimation:
Code:
void TryShinyAnimation(u8 battler, struct Pokemon *mon)
{
bool8 isShiny;
u32 otId, personality;
u32 shinyValue;
u8 taskCirc, taskDgnl;
struct Pokemon* illusionMon;
// custom
u8 taskMetallicShine;
// end custom
isShiny = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = TRUE;
illusionMon = GetIllusionMonPtr(battler);
if (illusionMon != NULL)
mon = illusionMon;
otId = GetMonData(mon, MON_DATA_OT_ID);
personality = GetMonData(mon, MON_DATA_PERSONALITY);
if (IsBattlerSpriteVisible(battler) && IsValidForBattle(mon))
{
shinyValue = GET_SHINY_VALUE(otId, personality);
if (shinyValue < SHINY_ODDS)
isShiny = TRUE;
if (isShiny)
{
if (GetSpriteTileStartByTag(ANIM_TAG_GOLD_STARS) == 0xFFFF)
{
LoadCompressedSpriteSheetUsingHeap(&gBattleAnimPicTable[ANIM_TAG_GOLD_STARS - ANIM_SPRITES_START]);
LoadCompressedSpritePaletteUsingHeap(&gBattleAnimPaletteTable[ANIM_TAG_GOLD_STARS - ANIM_SPRITES_START]);
}
taskCirc = CreateTask(Task_ShinyStars, 10);
taskDgnl = CreateTask(Task_ShinyStars, 10);
gTasks[taskCirc].tBattler = battler;
gTasks[taskDgnl].tBattler = battler;
gTasks[taskCirc].tStarMove = SHINY_STAR_ENCIRCLE;
gTasks[taskDgnl].tStarMove = SHINY_STAR_DIAGONAL;
return;
}
// custom
if (GetMonData(mon, MON_DATA_SPECIES) == SPECIES_TREECKO)
{
taskMetallicShine = CreateTask(AnimTask_MetallicShineCopy, 10);
gBattleAnimArgs[1] = TRUE;
gBattleAnimArgs[2] = RGB(0,10,20);
return;
}
// end custom
}
gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = TRUE;
}
inserted between functions SpriteCB_ShinyStars_Encircle and AnimTask_LoadPokeblockGfx:
Code:
#define tTimer data[13]
void AnimTask_MetallicShineCopy(u8 taskId)
{
u16 species;
u8 spriteId;
u8 newSpriteId;
u16 paletteNum;
struct BattleAnimBgData animBg;
bool32 priorityChanged = FALSE;
if (gTasks[taskId].tTimer < 60)
{
gTasks[taskId].tTimer++;
return;
}
gBattle_WIN0H = 0;
gBattle_WIN0V = 0;
SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR | WINOUT_WIN01_BG0 | WINOUT_WIN01_BG2 | WINOUT_WIN01_BG3 | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR);
SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJWIN_ON);
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG1);
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(8, 12));
SetAnimBgAttribute(1, BG_ANIM_PRIORITY, 0);
SetAnimBgAttribute(1, BG_ANIM_SCREEN_SIZE, 0);
if (!IsContest())
SetAnimBgAttribute(1, BG_ANIM_CHAR_BASE_BLOCK, 1);
if (IsDoubleBattle() && !IsContest())
{
if (GetBattlerPosition(gBattleAnimAttacker) == B_POSITION_OPPONENT_RIGHT || GetBattlerPosition(gBattleAnimAttacker) == B_POSITION_PLAYER_LEFT)
{
if (IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimAttacker)) == TRUE)
{
gSprites[gBattlerSpriteIds[BATTLE_PARTNER(gBattleAnimAttacker)]].oam.priority--;
SetAnimBgAttribute(1, BG_ANIM_PRIORITY, 1);
priorityChanged = TRUE;
}
}
}
if (IsContest())
{
species = gContestResources->moveAnim->species;
}
else
{
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_SPECIES);
else
species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_SPECIES);
}
spriteId = GetAnimBattlerSpriteId(ANIM_ATTACKER);
newSpriteId = CreateInvisibleSpriteCopy(gBattleAnimAttacker, spriteId, species);
GetBattleAnimBg1Data(&animBg);
AnimLoadCompressedBgTilemap(animBg.bgId, gMetalShineTilemap);
AnimLoadCompressedBgGfx(animBg.bgId, gMetalShineGfx, animBg.tilesOffset);
LoadCompressedPalette(gMetalShinePalette, BG_PLTT_ID(animBg.paletteId), PLTT_SIZE_4BPP);
gBattle_BG1_X = -gSprites[spriteId].x + 96;
gBattle_BG1_Y = -gSprites[spriteId].y + 32;
paletteNum = 16 + gSprites[spriteId].oam.paletteNum;
if (gBattleAnimArgs[1] == 0)
SetGrayscaleOrOriginalPalette(paletteNum, FALSE);
else
BlendPalette(BG_PLTT_ID(paletteNum), 16, 11, gBattleAnimArgs[2]);
gTasks[taskId].data[0] = newSpriteId;
gTasks[taskId].data[1] = gBattleAnimArgs[0];
gTasks[taskId].data[2] = gBattleAnimArgs[1];
gTasks[taskId].data[3] = gBattleAnimArgs[2];
gTasks[taskId].data[6] = priorityChanged;
gTasks[taskId].func = AnimTask_MetallicShine_StepCopy;
}
static void AnimTask_MetallicShine_StepCopy(u8 taskId)
{
struct BattleAnimBgData animBg;
u16 paletteNum;
u8 spriteId;
gTasks[taskId].data[10] += 4;
gBattle_BG1_X -= 4;
if (gTasks[taskId].data[10] == 128)
{
gTasks[taskId].data[10] = 0;
gBattle_BG1_X += 128;
gTasks[taskId].data[11]++;
if (gTasks[taskId].data[11] == 2)
{
spriteId = GetAnimBattlerSpriteId(ANIM_ATTACKER);
paletteNum = 16 + gSprites[spriteId].oam.paletteNum;
if (gTasks[taskId].data[1] == 0)
SetGrayscaleOrOriginalPalette(paletteNum, TRUE);
DestroySprite(&gSprites[gTasks[taskId].data[0]]);
GetBattleAnimBg1Data(&animBg);
ClearBattleAnimBg(animBg.bgId);
if (gTasks[taskId].data[6] == 1)
gSprites[gBattlerSpriteIds[BATTLE_PARTNER(gBattleAnimAttacker)]].oam.priority++;
}
else if (gTasks[taskId].data[11] == 3)
{
gBattle_WIN0H = 0;
gBattle_WIN0V = 0;
SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR | WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR);
if (!IsContest())
SetAnimBgAttribute(1, BG_ANIM_CHAR_BASE_BLOCK, 0);
SetGpuReg(REG_OFFSET_DISPCNT, GetGpuReg(REG_OFFSET_DISPCNT) ^ DISPCNT_OBJWIN_ON);
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
DestroyAnimVisualTask(taskId);
}
}
}
#undef tTimer
Last edited: