#include "global.h" #include "constants/battle_anim.h" #include "constants/species.h" #include "rom_8077ABC.h" #include "battle.h" #include "battle_anim.h" #include "blend_palette.h" #include "contest.h" #include "data2.h" #include "decompress.h" #include "palette.h" #include "pokemon_icon.h" #include "sprite.h" #include "task.h" #include "trig.h" #include "util.h" #include "ewram.h" #define GET_UNOWN_LETTER(personality) ((\ (((personality & 0x03000000) >> 24) << 6) \ | (((personality & 0x00030000) >> 16) << 4) \ | (((personality & 0x00000300) >> 8) << 2) \ | (((personality & 0x00000003) >> 0) << 0) \ ) % 28) #define IS_DOUBLE_BATTLE() ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) ? TRUE : FALSE) #define NUM_BATTLE_SLOTS 4 #define gBattleMonPartyPositions gBattlerPartyIndexes #define gCastformElevations gUnknownCastformData_0837F5A8 #define gCastformBackSpriteYCoords gUnknown_0837F5AC #define gTransformPersonalities gTransformedPersonalities #define gBattleMonSprites gBattlerSpriteIds struct Struct_gUnknown_0837F578 { u8 field_0; u8 field_1; }; struct Struct_2017810 { u8 filler_0[6]; u8 field_6; u8 filler_7[5]; }; #define BG1CNT (*(vBgCnt *)REG_ADDR_BG1CNT) #define BG2CNT (*(vBgCnt *)REG_ADDR_BG2CNT) #define BG3CNT (*(vBgCnt *)REG_ADDR_BG3CNT) extern const union AnimCmd *const gDummySpriteAnimTable[]; extern const union AffineAnimCmd *const gDummySpriteAffineAnimTable[]; extern u16 gBattleMonPartyPositions[]; extern u16 gBattleTypeFlags; extern u32 gTransformPersonalities[NUM_BATTLE_SLOTS]; extern u8 gBattleMonForms[NUM_BATTLE_SLOTS]; extern u16 gAnimSpeciesByBanks[]; extern u8 gBattleMonSprites[NUM_BATTLE_SLOTS]; extern u8 gBattleAnimAttacker; extern u8 gBattleAnimTarget; extern s16 gBattleAnimArgs[8]; extern u8 gBattlerPositions[NUM_BATTLE_SLOTS]; extern u8 gBattlersCount; // gNumBattleMons? extern struct OamMatrix gOamMatrices[]; extern struct Struct_2017810 unk_2017810[]; extern u8 gAnimFriendship; extern u8 UpdateMonIconFrame(struct Sprite *sprite); EWRAM_DATA union AffineAnimCmd *gUnknown_0202F7D4 = NULL; EWRAM_DATA u32 filler_0202F7D8[3] = {0}; const struct Struct_gUnknown_0837F578 gUnknown_0837F578[][4] = { { { 72, 80 }, { 176, 40 }, { 48, 40 }, { 112, 80 }, }, { { 32, 80 }, { 200, 40 }, { 90, 88 }, { 152, 32 }, }, }; // One entry for each of the four Castform forms. // Coords are probably front pic coords or back pic coords, but this data does not seem to be // used during battle, party summary, or pokedex screens. const struct MonCoords gCastformFrontSpriteCoords[] = { { 0x44, 17 }, // NORMAL { 0x66, 9 }, // SUN { 0x46, 9 }, // RAIN { 0x86, 8 }, // HAIL }; const u8 gCastformElevations[] = { 13, // NORMAL 14, // SUN 13, // RAIN 13, // HAIL }; // Y position of the backsprite for each of the four Castform forms. const u8 gCastformBackSpriteYCoords[] = { 0, // NORMAL 0, // SUN 0, // RAIN 0, // HAIL }; const struct SpriteTemplate gSpriteTemplate_837F5B0[] = { { .tileTag = 55125, .paletteTag = 55125, .oam = &gOamData_837DF9C, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy, }, { .tileTag = 55126, .paletteTag = 55126, .oam = &gOamData_837DF9C, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy, } }; const struct SpriteSheet gUnknown_0837F5E0[] = { { gMiscBlank_Gfx, 0x800, 55125, }, { gMiscBlank_Gfx, 0x800, 55126, }, }; // pkmn_form.c u8 GetBattlerSpriteCoord(u8 slot, u8 a2) { u8 var; u16 species; struct BattleSpriteInfo *transform; if (IsContest()) { if (a2 == 3 && slot == 3) a2 = 1; } switch (a2) { case 0: case 2: var = gUnknown_0837F578[IS_DOUBLE_BATTLE()][GetBattlerPosition(slot)].field_0; break; case 1: var = gUnknown_0837F578[IS_DOUBLE_BATTLE()][GetBattlerPosition(slot)].field_1; break; case 3: case 4: default: if (IsContest()) { if (gContestResources__moveAnim.hasTargetAnim) species = gContestResources__moveAnim.targetSpecies; else species = gContestResources__moveAnim.species; } else { if (GetBattlerSide(slot)) { transform = &gBattleSpriteInfo[slot]; if (!transform->transformedSpecies) species = GetMonData(&gEnemyParty[gBattleMonPartyPositions[slot]], MON_DATA_SPECIES); else species = transform->transformedSpecies; } else { transform = &gBattleSpriteInfo[slot]; if (!transform->transformedSpecies) species = GetMonData(&gPlayerParty[gBattleMonPartyPositions[slot]], MON_DATA_SPECIES); else species = transform->transformedSpecies; } } if (a2 == 3) var = GetBattlerSpriteFinal_Y(slot, species, 1); else var = GetBattlerSpriteFinal_Y(slot, species, 0); break; } return var; } u8 sub_8077BFC(u8 slot, u16 species) { u16 letter; u32 personality; struct BattleSpriteInfo *transform; u8 ret; u16 var; if (GetBattlerSide(slot) == 0 || IsContest()) { if (species == SPECIES_UNOWN) { if (IsContest()) { if (gContestResources__moveAnim.hasTargetAnim) personality = gContestResources__moveAnim.targetPersonality; else personality = gContestResources__moveAnim.personality; } else { transform = &gBattleSpriteInfo[slot]; if (!transform->transformedSpecies) personality = GetMonData(&gPlayerParty[gBattleMonPartyPositions[slot]], MON_DATA_PERSONALITY); else personality = gTransformPersonalities[slot]; } letter = GET_UNOWN_LETTER(personality); if (!letter) var = species; else var = letter + SPECIES_UNOWN_B - 1; ret = gMonBackPicCoords[var].y_offset; } else if (species == SPECIES_CASTFORM) { ret = gCastformBackSpriteYCoords[gBattleMonForms[slot]]; } else if (species > NUM_SPECIES) { ret = gMonBackPicCoords[0].y_offset; } else { ret = gMonBackPicCoords[species].y_offset; } } else { if (species == SPECIES_UNOWN) { transform = &gBattleSpriteInfo[slot]; if (!transform->transformedSpecies) personality = GetMonData(&gEnemyParty[gBattleMonPartyPositions[slot]], MON_DATA_PERSONALITY); else personality = gTransformPersonalities[slot]; letter = GET_UNOWN_LETTER(personality); if (!letter) var = species; else var = letter + SPECIES_UNOWN_B - 1; ret = gMonFrontPicCoords[var].y_offset; } else if (species == SPECIES_CASTFORM) { ret = gCastformFrontSpriteCoords[gBattleMonForms[slot]].y_offset; } else if (species > NUM_SPECIES) { ret = gMonFrontPicCoords[0].y_offset; } else { ret = gMonFrontPicCoords[species].y_offset; } } return ret; } u8 sub_8077DD8(u8 slot, u16 species) { u8 ret = 0; if (GetBattlerSide(slot) == 1) { if (!IsContest()) { if (species == SPECIES_CASTFORM) ret = gCastformElevations[gBattleMonForms[slot]]; else if (species > NUM_SPECIES) ret = gEnemyMonElevation[0]; else ret = gEnemyMonElevation[species]; } } return ret; } u8 GetBattlerSpriteFinal_Y(u8 slot, u16 species, u8 a3) { u16 offset; u8 y; if (GetBattlerSide(slot) == 0 || IsContest()) { offset = sub_8077BFC(slot, species); } else { offset = sub_8077BFC(slot, species); offset -= sub_8077DD8(slot, species); } y = offset + gUnknown_0837F578[IS_DOUBLE_BATTLE()][GetBattlerPosition(slot)].field_1; if (a3) { if (GetBattlerSide(slot) == 0) y += 8; if (y > 104) y = 104; } return y; } u8 sub_8077EE4(u8 slot, u8 a2) { u16 species; struct BattleSpriteInfo *transform; if (a2 == 3 || a2 == 4) { if (IsContest()) { if (gContestResources__moveAnim.hasTargetAnim) species = gContestResources__moveAnim.targetSpecies; else species = gContestResources__moveAnim.species; } else { transform = &gBattleSpriteInfo[slot]; if (!transform->transformedSpecies) species = gAnimSpeciesByBanks[slot]; else species = transform->transformedSpecies; } if (a2 == 3) return GetBattlerSpriteFinal_Y(slot, species, 1); else return GetBattlerSpriteFinal_Y(slot, species, 0); } else { return GetBattlerSpriteCoord(slot, a2); } } u8 sub_8077F68(u8 slot) { return GetBattlerSpriteCoord(slot, 4); } u8 sub_8077F7C(u8 slot) { u16 var; if (GetBattlerSide(slot) != 0) var = GetBattlerSpriteCoord(slot, 1) + 16; else var = GetBattlerSpriteCoord(slot, 1) + 17; return var; } u8 sub_8077FC0(u8 slot) { u16 var; u8 r6; struct BattleSpriteInfo *transform; r6 = GetBattlerSpriteCoord(slot, 1); if (!IsContest()) { if (GetBattlerSide(slot) != 0) { transform = &gBattleSpriteInfo[slot]; if (!transform->transformedSpecies) { var = GetMonData(&gEnemyParty[gBattleMonPartyPositions[slot]], MON_DATA_SPECIES); } else { var = transform->transformedSpecies; } } else { transform = &gBattleSpriteInfo[slot]; if (!transform->transformedSpecies) var = GetMonData(&gPlayerParty[gBattleMonPartyPositions[slot]], MON_DATA_SPECIES); else var = transform->transformedSpecies; } if (GetBattlerSide(slot) != 0) r6 -= sub_8077DD8(slot, var); } return r6; } u8 GetAnimBattlerSpriteId(u8 whichBank) { u8 *sprites; if (whichBank == ANIM_BATTLER_ATTACKER) { if (IsBankSpritePresent(gBattleAnimAttacker)) { sprites = gBattleMonSprites; return sprites[gBattleAnimAttacker]; } else { return 0xff; } } else if (whichBank == ANIM_BATTLER_TARGET) { if (IsBankSpritePresent(gBattleAnimTarget)) { sprites = gBattleMonSprites; return sprites[gBattleAnimTarget]; } else { return 0xff; } } else if (whichBank == ANIM_BATTLER_ATK_PARTNER) { if (!IsAnimBankSpriteVisible(gBattleAnimAttacker ^ 2)) return 0xff; else return gBattleMonSprites[gBattleAnimAttacker ^ 2]; } else { if (IsAnimBankSpriteVisible(gBattleAnimTarget ^ 2)) return gBattleMonSprites[gBattleAnimTarget ^ 2]; else return 0xff; } } void StoreSpriteCallbackInData(struct Sprite *sprite, void (*callback)(struct Sprite*)) { sprite->data[6] = (u32)(callback) & 0xffff; sprite->data[7] = (u32)(callback) >> 16; } void SetCallbackToStoredInData(struct Sprite *sprite) { u32 callback = (u16)sprite->data[6] | (sprite->data[7] << 16); sprite->callback = (void (*)(struct Sprite *))callback; } void sub_8078114(struct Sprite *sprite) { if (sprite->data[3]) { sprite->x2 = Sin(sprite->data[0], sprite->data[1]); sprite->y2 = Cos(sprite->data[0], sprite->data[1]); sprite->data[0] += sprite->data[2]; if (sprite->data[0] >= 0x100) sprite->data[0] -= 0x100; else if (sprite->data[0] < 0) sprite->data[0] += 0x100; sprite->data[3]--; } else { SetCallbackToStoredInData(sprite); } } void sub_8078174(struct Sprite *sprite) { if (sprite->data[3]) { sprite->x2 = Sin(sprite->data[0], (sprite->data[5] >> 8) + sprite->data[1]); sprite->y2 = Cos(sprite->data[0], (sprite->data[5] >> 8) + sprite->data[1]); sprite->data[0] += sprite->data[2]; sprite->data[5] += sprite->data[4]; if (sprite->data[0] >= 0x100) sprite->data[0] -= 0x100; else if (sprite->data[0] < 0) sprite->data[0] += 0x100; sprite->data[3]--; } else { SetCallbackToStoredInData(sprite); } } void unref_sub_80781F0(struct Sprite *sprite) { if (sprite->data[3]) { sprite->x2 = Sin(sprite->data[0], sprite->data[1]); sprite->y2 = Cos(sprite->data[4], sprite->data[1]); sprite->data[0] += sprite->data[2]; sprite->data[4] += sprite->data[5]; if (sprite->data[0] >= 0x100) sprite->data[0] -= 0x100; else if (sprite->data[0] < 0) sprite->data[0] += 0x100; if (sprite->data[4] >= 0x100) sprite->data[4] -= 0x100; else if (sprite->data[4] < 0) sprite->data[4] += 0x100; sprite->data[3]--; } else { SetCallbackToStoredInData(sprite); } } void sub_8078278(struct Sprite *sprite) { if (sprite->data[3]) { sprite->x2 = Sin(sprite->data[0], sprite->data[1]); sprite->y2 = Cos(sprite->data[0], sprite->data[4]); sprite->data[0] += sprite->data[2]; if (sprite->data[0] >= 0x100) sprite->data[0] -= 0x100; else if (sprite->data[0] < 0) sprite->data[0] += 0x100; sprite->data[3]--; } else { SetCallbackToStoredInData(sprite); } } // Simply waits until the sprite's data[0] hits zero. // This is used to let sprite anims or affine anims to run for a designated // duration. void WaitAnimForDuration(struct Sprite *sprite) { if (sprite->data[0] > 0) sprite->data[0]--; else SetCallbackToStoredInData(sprite); } void sub_80782F8(struct Sprite *sprite) { sub_8078314(sprite); sprite->callback = TranslateSpriteOverDuration; sprite->callback(sprite); } void sub_8078314(struct Sprite *sprite) { s16 old; int v1; if (sprite->data[1] > sprite->data[2]) sprite->data[0] = -sprite->data[0]; v1 = sprite->data[2] - sprite->data[1]; old = sprite->data[0]; sprite->data[0] = abs(v1 / sprite->data[0]); sprite->data[2] = (sprite->data[4] - sprite->data[3]) / sprite->data[0]; sprite->data[1] = old; } void TranslateSpriteOverDuration(struct Sprite *sprite) { if (sprite->data[0] > 0) { sprite->data[0]--; sprite->x2 += sprite->data[1]; sprite->y2 += sprite->data[2]; } else { SetCallbackToStoredInData(sprite); } } void sub_8078394(struct Sprite *sprite) { if (sprite->data[0] > 0) { sprite->data[0]--; sprite->data[3] += sprite->data[1]; sprite->data[4] += sprite->data[2]; sprite->x2 = sprite->data[3] >> 8; sprite->y2 = sprite->data[4] >> 8; } else { SetCallbackToStoredInData(sprite); } } void sub_80783D0(struct Sprite *sprite) { if (sprite->data[0] > 0) { sprite->data[0]--; sprite->data[3] += sprite->data[1]; sprite->data[4] += sprite->data[2]; sprite->x2 = sprite->data[3] >> 8; sprite->y2 = sprite->data[4] >> 8; } else { SetCallbackToStoredInData(sprite); } UpdateMonIconFrame(sprite); } void unref_sub_8078414(struct Sprite *sprite) { sprite->data[1] = sprite->x + sprite->x2; sprite->data[3] = sprite->y + sprite->y2; sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, 2); sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, 3); sprite->callback = sub_80782F8; } void TranslateMonBGUntil(struct Sprite *sprite) { if (sprite->data[0] > 0) { sprite->data[0]--; gSprites[sprite->data[3]].x2 += sprite->data[1]; gSprites[sprite->data[3]].y2 += sprite->data[2]; } else { SetCallbackToStoredInData(sprite); } } // Same as TranslateMonBGUntil, but it operates on sub-pixel values // to handle slower translations. void TranslateMonBGSubPixelUntil(struct Sprite *sprite) { if (sprite->data[0] > 0) { sprite->data[0]--; sprite->data[3] += sprite->data[1]; sprite->data[4] += sprite->data[2]; gSprites[sprite->data[5]].x2 = sprite->data[3] >> 8; gSprites[sprite->data[5]].y2 = sprite->data[4] >> 8; } else { SetCallbackToStoredInData(sprite); } } void sub_8078504(struct Sprite *sprite) { if (sprite->data[0] > 0) { sprite->data[0]--; sprite->x2 = sprite->data[2] >> 8; sprite->data[2] += sprite->data[1]; sprite->y2 = sprite->data[4] >> 8; sprite->data[4] += sprite->data[3]; if (sprite->data[0] % sprite->data[5] == 0) { if (sprite->data[5]) sprite->invisible ^= 1; } } else { SetCallbackToStoredInData(sprite); } } void DestroySpriteAndMatrix(struct Sprite *sprite) { FreeSpriteOamMatrix(sprite); DestroyAnimSprite(sprite); } void unref_sub_8078588(struct Sprite *sprite) { sprite->data[1] = sprite->x + sprite->x2; sprite->data[3] = sprite->y + sprite->y2; sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimAttacker, 2); sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimAttacker, 3); sprite->callback = sub_80782F8; } void unref_sub_80785CC(struct Sprite *sprite) { ResetPaletteStructByUid(sprite->data[5]); DestroySpriteAndMatrix(sprite); } void sub_80785E4(struct Sprite *sprite) { if (sprite->affineAnimEnded) SetCallbackToStoredInData(sprite); } void sub_8078600(struct Sprite *sprite) { if (sprite->animEnded) SetCallbackToStoredInData(sprite); } void sub_807861C(struct Sprite *sprite) { REG_BLDCNT = 0; REG_BLDALPHA = 0; DestroyAnimSprite(sprite); } void sub_8078634(u8 task) { REG_BLDCNT = 0; REG_BLDALPHA = 0; DestroyAnimVisualTask(task); } void sub_8078650(struct Sprite *sprite) { sprite->x = GetBattlerSpriteCoord(gBattleAnimAttacker, 2); sprite->y = GetBattlerSpriteCoord(gBattleAnimAttacker, 3); } void sub_807867C(struct Sprite *sprite, s16 a2) { u16 v1 = GetBattlerSpriteCoord(gBattleAnimAttacker, 0); u16 v2 = GetBattlerSpriteCoord(gBattleAnimTarget, 0); if (v1 > v2) { sprite->x -= a2; } else if (v1 < v2) { sprite->x += a2; } else { if (GetBattlerSide(gBattleAnimAttacker) != 0) sprite->x -= a2; else sprite->x += a2; } } void InitAnimArcTranslation(struct Sprite *sprite) { sprite->data[1] = sprite->x; sprite->data[3] = sprite->y; InitAnimLinearTranslation(sprite); sprite->data[6] = 0x8000 / sprite->data[0]; sprite->data[7] = 0; } bool8 TranslateAnimArc(struct Sprite *sprite) { if (TranslateAnimLinear(sprite)) return TRUE; sprite->data[7] += sprite->data[6]; sprite->y2 += Sin((u8)(sprite->data[7] >> 8), sprite->data[5]); return FALSE; } void oamt_add_pos2_onto_pos1(struct Sprite *sprite) { sprite->x += sprite->x2; sprite->y += sprite->y2; sprite->x2 = 0; sprite->y2 = 0; } void sub_8078764(struct Sprite *sprite, bool8 a2) { if (!a2) { sprite->x = sub_8077EE4(gBattleAnimTarget, 0); sprite->y = sub_8077EE4(gBattleAnimTarget, 1); } sub_807867C(sprite, gBattleAnimArgs[0]); sprite->y += gBattleAnimArgs[1]; } void InitAnimSpritePos(struct Sprite *sprite, u8 a2) { if (!a2) { sprite->x = sub_8077EE4(gBattleAnimAttacker, 0); sprite->y = sub_8077EE4(gBattleAnimAttacker, 1); } else { sprite->x = sub_8077EE4(gBattleAnimAttacker, 2); sprite->y = sub_8077EE4(gBattleAnimAttacker, 3); } sub_807867C(sprite, gBattleAnimArgs[0]); sprite->y += gBattleAnimArgs[1]; } u8 GetBattlerSide(u8 slot) { return gBattlerPositions[slot] & 1; } u8 GetBattlerPosition(u8 slot) { return gBattlerPositions[slot]; } u8 GetBattlerAtPosition(u8 slot) { u8 i; for (i = 0; i < gBattlersCount; i++) { if (gBattlerPositions[i] == slot) break; } return i; } bool8 IsBankSpritePresent(u8 slot) { if (IsContest()) { if (gBattleAnimAttacker == slot) return TRUE; if (gBattleAnimTarget == slot) return TRUE; return FALSE; } else { if (gBattlerPositions[slot] == 0xff) return FALSE; if (GetBattlerSide(slot) != B_SIDE_PLAYER) { if (GetMonData(&gEnemyParty[gBattleMonPartyPositions[slot]], MON_DATA_HP) != 0) return TRUE; } else { if (GetMonData(&gPlayerParty[gBattleMonPartyPositions[slot]], MON_DATA_HP) != 0) return TRUE; } return FALSE; } } bool8 IsDoubleBattle() { return IS_DOUBLE_BATTLE(); } void sub_8078914(struct Struct_sub_8078914 *unk) { if (IsContest()) { unk->field_0 = (u8 *)(VRAM + 0x8000); unk->field_4 = (u8 *)(VRAM + 0xf000); unk->field_8 = 0xe; } else { unk->field_0 = (u8 *)(VRAM + 0x4000); unk->field_4 = (u8 *)(VRAM + 0xe000); unk->field_8 = 0x8; } } void sub_8078954(struct Struct_sub_8078914 *unk, u8 b) { if (IsContest()) { unk->field_0 = (u8 *)(VRAM + 0x8000); unk->field_4 = (u8 *)(VRAM + 0xf000); unk->field_8 = 0xe; } else if (GetBattlerPosition_permutated(gBattleAnimAttacker) == 1) { unk->field_0 = (u8 *)(VRAM + 0x4000); unk->field_4 = (u8 *)(VRAM + 0xe000); unk->field_8 = 0x8; } else { unk->field_0 = (u8 *)(VRAM + 0x6000); unk->field_4 = (u8 *)(VRAM + 0xf000); unk->field_8 = 0x9; } } u8 sub_80789BC() { if (IsContest()) return 1; return 2; } void sub_80789D4(bool8 a1) { if (!a1) { BG3CNT.screenSize = 0; BG3CNT.areaOverflowMode = 1; } else if (IsContest()) { BG3CNT.screenSize = 0; BG3CNT.areaOverflowMode = 1; } else { BG3CNT.screenSize = 1; BG3CNT.areaOverflowMode = 0; } } void sub_8078A34(struct Sprite *sprite) { sprite->data[1] = sprite->x; sprite->data[3] = sprite->y; InitSpriteDataForLinearTranslation(sprite); sprite->callback = sub_80783D0; sprite->callback(sprite); } void InitSpriteDataForLinearTranslation(struct Sprite *sprite) { s16 x = (sprite->data[2] - sprite->data[1]) << 8; s16 y = (sprite->data[4] - sprite->data[3]) << 8; sprite->data[1] = x / sprite->data[0]; sprite->data[2] = y / sprite->data[0]; sprite->data[4] = 0; sprite->data[3] = 0; } void InitAnimLinearTranslation(struct Sprite *sprite) { int x = sprite->data[2] - sprite->data[1]; int y = sprite->data[4] - sprite->data[3]; bool8 movingLeft = x < 0; bool8 movingUp = y < 0; u16 xDelta = abs(x) << 8; u16 yDelta = abs(y) << 8; xDelta = xDelta / sprite->data[0]; yDelta = yDelta / sprite->data[0]; if (movingLeft) xDelta |= 1; else xDelta &= ~1; if (movingUp) yDelta |= 1; else yDelta &= ~1; sprite->data[1] = xDelta; sprite->data[2] = yDelta; sprite->data[4] = 0; sprite->data[3] = 0; } void StartAnimLinearTranslation(struct Sprite *sprite) { sprite->data[1] = sprite->x; sprite->data[3] = sprite->y; InitAnimLinearTranslation(sprite); sprite->callback = TranslateAnimLinearUntil; sprite->callback(sprite); } bool8 TranslateAnimLinear(struct Sprite *sprite) { u16 v1, v2, x, y; if (!sprite->data[0]) return TRUE; v1 = sprite->data[1]; v2 = sprite->data[2]; x = sprite->data[3]; y = sprite->data[4]; x += v1; y += v2; if (v1 & 1) sprite->x2 = -(x >> 8); else sprite->x2 = x >> 8; if (v2 & 1) sprite->y2 = -(y >> 8); else sprite->y2 = y >> 8; sprite->data[3] = x; sprite->data[4] = y; sprite->data[0]--; return FALSE; } void TranslateAnimLinearUntil(struct Sprite *sprite) { if (TranslateAnimLinear(sprite)) SetCallbackToStoredInData(sprite); } void sub_8078BD4(struct Sprite *sprite) { int v1 = abs(sprite->data[2] - sprite->data[1]) << 8; sprite->data[0] = v1 / sprite->data[0]; InitAnimLinearTranslation(sprite); } void sub_8078C00(struct Sprite *sprite) { sprite->data[1] = sprite->x; sprite->data[3] = sprite->y; sub_8078BD4(sprite); sprite->callback = TranslateAnimLinearUntil; sprite->callback(sprite); } void sub_8078C28(struct Sprite *sprite) { int x = sprite->data[2] - sprite->data[1]; int y = sprite->data[4] - sprite->data[3]; bool8 x_sign = x < 0; bool8 y_sign = y < 0; u16 x2 = abs(x) << 4; u16 y2 = abs(y) << 4; x2 /= sprite->data[0]; y2 /= sprite->data[0]; if (x_sign) x2 |= 1; else x2 &= ~1; if (y_sign) y2 |= 1; else y2 &= ~1; sprite->data[1] = x2; sprite->data[2] = y2; sprite->data[4] = 0; sprite->data[3] = 0; } void sub_8078CC0(struct Sprite *sprite) { sprite->data[1] = sprite->x; sprite->data[3] = sprite->y; sub_8078C28(sprite); sprite->callback = sub_8078D44; sprite->callback(sprite); } bool8 sub_8078CE8(struct Sprite *sprite) { u16 v1, v2, x, y; if (!sprite->data[0]) return TRUE; v1 = sprite->data[1]; v2 = sprite->data[2]; x = sprite->data[3]; y = sprite->data[4]; x += v1; y += v2; if (v1 & 1) sprite->x2 = -(x >> 4); else sprite->x2 = x >> 4; if (v2 & 1) sprite->y2 = -(y >> 4); else sprite->y2 = y >> 4; sprite->data[3] = x; sprite->data[4] = y; sprite->data[0]--; return FALSE; } void sub_8078D44(struct Sprite *sprite) { if (sub_8078CE8(sprite)) SetCallbackToStoredInData(sprite); } void sub_8078D60(struct Sprite *sprite) { int v1 = abs(sprite->data[2] - sprite->data[1]) << 4; sprite->data[0] = v1 / sprite->data[0]; sub_8078C28(sprite); } void sub_8078D8C(struct Sprite *sprite) { sprite->data[1] = sprite->x; sprite->data[3] = sprite->y; sub_8078D60(sprite); sprite->callback = sub_8078D44; sprite->callback(sprite); } void obj_id_set_rotscale(u8 sprite, s16 xScale, s16 yScale, u16 rotation) { int i; struct ObjAffineSrcData src; struct OamMatrix matrix; src.xScale = xScale; src.yScale = yScale; src.rotation = rotation; if (sub_8078E38()) src.xScale = -src.xScale; i = gSprites[sprite].oam.matrixNum; ObjAffineSet(&src, &matrix, 1, 2); gOamMatrices[i].a = matrix.a; gOamMatrices[i].b = matrix.b; gOamMatrices[i].c = matrix.c; gOamMatrices[i].d = matrix.d; } bool8 sub_8078E38() { if (IsContest()) { if (gSprites[GetAnimBattlerSpriteId(0)].data[2] == 0xc9 /* XXX SPECIES_UNOWN? */) return FALSE; return TRUE; } return FALSE; } void PrepareBattlerSpriteForRotScale(u8 sprite, u8 objMode) { u8 r7 = gSprites[sprite].data[0]; if (IsContest() || IsAnimBankSpriteVisible(r7)) gSprites[sprite].invisible = FALSE; gSprites[sprite].oam.objMode = objMode; gSprites[sprite].affineAnimPaused = TRUE; if (!IsContest() && !gSprites[sprite].oam.affineMode) gSprites[sprite].oam.matrixNum = ewram17810[r7].unk6; gSprites[sprite].oam.affineMode = 3; CalcCenterToCornerVec(&gSprites[sprite], gSprites[sprite].oam.shape, gSprites[sprite].oam.size, gSprites[sprite].oam.affineMode); } void sub_8078F40(u8 sprite) { obj_id_set_rotscale(sprite, 0x100, 0x100, 0); gSprites[sprite].oam.affineMode = 1; gSprites[sprite].oam.objMode = 0; gSprites[sprite].affineAnimPaused = FALSE; CalcCenterToCornerVec(&gSprites[sprite], gSprites[sprite].oam.shape, gSprites[sprite].oam.size, gSprites[sprite].oam.affineMode); } void sub_8078F9C(u8 sprite) { u16 matrix = gSprites[sprite].oam.matrixNum; s16 c = gOamMatrices[matrix].c; if (c < 0) c = -c; gSprites[sprite].y2 = c >> 3; } // related to obj_id_set_rotscale void sub_8078FDC(struct Sprite *sprite, bool8 a2, s16 xScale, s16 yScale, u16 rotation) { int i; struct ObjAffineSrcData src; struct OamMatrix matrix; if (sprite->oam.affineMode & 1) { sprite->affineAnimPaused = TRUE; if (a2) CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); src.xScale = xScale; src.yScale = yScale; src.rotation = rotation; if (sub_8078E38()) src.xScale = -src.xScale; i = sprite->oam.matrixNum; ObjAffineSet(&src, &matrix, 1, 2); gOamMatrices[i].a = matrix.a; gOamMatrices[i].b = matrix.b; gOamMatrices[i].c = matrix.c; gOamMatrices[i].d = matrix.d; } } void sub_8079098(struct Sprite *sprite) { sub_8078FDC(sprite, TRUE, 0x100, 0x100, 0); sprite->affineAnimPaused = FALSE; CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); } static u16 ArcTan2_(s16 a, s16 b) { return ArcTan2(a, b); } u16 ArcTan2Neg(s16 a, s16 b) { u16 var = ArcTan2_(a, b); return -var; } void sub_8079108(u16 a1, bool8 a2) { int i; struct PlttData *c; struct PlttData *c2; u16 average; a1 *= 0x10; if (!a2) { for (i = 0; i < 0x10; i++) { c = (struct PlttData *)&gPlttBufferUnfaded[a1 + i]; average = c->r + c->g + c->b; average /= 3; c2 = (struct PlttData *)&gPlttBufferFaded[a1 + i]; c2->r = average; c2->g = average; c2->b = average; } } else { CpuCopy32(&gPlttBufferUnfaded[a1], &gPlttBufferFaded[a1], 0x20); } } u32 sub_80791A8(u8 a1, u8 a2, u8 a3, u8 a4, u8 a5, u8 a6, u8 a7) { u32 var = 0; u32 shift; if (a1) { if (!IsContest()) var = 0xe; else var = 1 << sub_80789BC(); } if (a2) { shift = gBattleAnimAttacker + 16; var |= 1 << shift; } if (a3) { shift = gBattleAnimTarget + 16; var |= 1 << shift; } if (a4) { if (IsAnimBankSpriteVisible(gBattleAnimAttacker ^ 2)) { shift = (gBattleAnimAttacker ^ 2) + 16; var |= 1 << shift; } } if (a5) { if (IsAnimBankSpriteVisible(gBattleAnimTarget ^ 2)) { shift = (gBattleAnimTarget ^ 2) + 16; var |= 1 << shift; } } if (a6) { if (!IsContest()) var |= 0x100; else var |= 0x4000; } if (a7) { if (!IsContest()) var |= 0x200; } return var; } u32 sub_80792C0(u8 a1, u8 a2, u8 a3, u8 a4) { u32 var = 0; u32 shift; if (IsContest()) { if (a1) { var |= 1 << 18; return var; } } else { if (a1) { if (IsAnimBankSpriteVisible(GetBattlerAtPosition(0))) { var |= 1 << (GetBattlerAtPosition(0) + 16); } } if (a2) { if (IsAnimBankSpriteVisible(GetBattlerAtPosition(2))) { shift = GetBattlerAtPosition(2) + 16; var |= 1 << shift; } } if (a3) { if (IsAnimBankSpriteVisible(GetBattlerAtPosition(1))) { shift = GetBattlerAtPosition(1) + 16; var |= 1 << shift; } } if (a4) { if (IsAnimBankSpriteVisible(GetBattlerAtPosition(3))) { shift = GetBattlerAtPosition(3) + 16; var |= 1 << shift; } } } return var; } u8 sub_80793A8(u8 a1) { return a1; } u8 unref_sub_80793B0(u8 a1) { return GetBattlerAtPosition(a1); } void sub_80793C4(struct Sprite *sprite) { bool8 var; if (!sprite->data[0]) { if (!gBattleAnimArgs[3]) var = TRUE; else var = FALSE; if (!gBattleAnimArgs[2]) InitAnimSpritePos(sprite, var); else sub_8078764(sprite, var); sprite->data[0]++; } else if (sprite->animEnded || sprite->affineAnimEnded) { DestroySpriteAndMatrix(sprite); } } // Linearly translates a sprite to a target position on the // other mon's sprite. // arg 0: initial x offset // arg 1: initial y offset // arg 2: target x offset // arg 3: target y offset // arg 4: duration // arg 5: lower 8 bits = location on attacking mon, upper 8 bits = location on target mon pick to target void TranslateAnimSpriteToTargetMonLocation(struct Sprite *sprite) { bool8 v1; u8 v2; if (!(gBattleAnimArgs[5] & 0xff00)) v1 = TRUE; else v1 = FALSE; if (!(gBattleAnimArgs[5] & 0xff)) v2 = 3; else v2 = 1; InitAnimSpritePos(sprite, v1); if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER) gBattleAnimArgs[2] = -gBattleAnimArgs[2]; sprite->data[0] = gBattleAnimArgs[4]; sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, 2) + gBattleAnimArgs[2]; sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, v2) + gBattleAnimArgs[3]; sprite->callback = StartAnimLinearTranslation; StoreSpriteCallbackInData(sprite, DestroyAnimSprite); } void sub_80794A8(struct Sprite *sprite) { InitAnimSpritePos(sprite, 1); if (GetBattlerSide(gBattleAnimAttacker)) gBattleAnimArgs[2] = -gBattleAnimArgs[2]; sprite->data[0] = gBattleAnimArgs[4]; sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, 2) + gBattleAnimArgs[2]; sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, 3) + gBattleAnimArgs[3]; sprite->data[5] = gBattleAnimArgs[5]; InitAnimArcTranslation(sprite); sprite->callback = sub_8079518; } void sub_8079518(struct Sprite *sprite) { if (TranslateAnimArc(sprite)) DestroyAnimSprite(sprite); } void sub_8079534(struct Sprite *sprite) { bool8 r4; u8 slot, r7; if (!gBattleAnimArgs[6]) { r4 = TRUE; r7 = 3; } else { r4 = FALSE; r7 = 1; } if (!gBattleAnimArgs[5]) { InitAnimSpritePos(sprite, r4); slot = gBattleAnimAttacker; } else { sub_8078764(sprite, r4); slot = gBattleAnimTarget; } if (GetBattlerSide(gBattleAnimAttacker)) gBattleAnimArgs[2] = -gBattleAnimArgs[2]; sub_8078764(sprite, r4); sprite->data[0] = gBattleAnimArgs[4]; sprite->data[2] = GetBattlerSpriteCoord(slot, 2) + gBattleAnimArgs[2]; sprite->data[4] = GetBattlerSpriteCoord(slot, r7) + gBattleAnimArgs[3]; sprite->callback = StartAnimLinearTranslation; StoreSpriteCallbackInData(sprite, DestroyAnimSprite); } s16 duplicate_obj_of_side_rel2move_in_transparent_mode(u8 a1) { u16 i; u8 sprite = GetAnimBattlerSpriteId(a1); if (sprite != 0xff) { for (i = 0; i < 0x40; i++) { if (!gSprites[i].inUse) { gSprites[i] = gSprites[sprite]; gSprites[i].oam.objMode = 1; gSprites[i].invisible = FALSE; return i; } } } return -1; } void obj_delete_but_dont_free_vram(struct Sprite *sprite) { sprite->usingSheet = TRUE; DestroySprite(sprite); } void sub_8079670(u8 task) { s16 v1 = 0; s16 v2 = 0; if (gBattleAnimArgs[2] > gBattleAnimArgs[0]) v2 = 1; if (gBattleAnimArgs[2] < gBattleAnimArgs[0]) v2 = -1; if (gBattleAnimArgs[3] > gBattleAnimArgs[1]) v1 = 1; if (gBattleAnimArgs[3] < gBattleAnimArgs[1]) v1 = -1; gTasks[task].data[0] = 0; gTasks[task].data[1] = gBattleAnimArgs[4]; gTasks[task].data[2] = 0; gTasks[task].data[3] = gBattleAnimArgs[0]; gTasks[task].data[4] = gBattleAnimArgs[1]; gTasks[task].data[5] = v2; gTasks[task].data[6] = v1; gTasks[task].data[7] = gBattleAnimArgs[2]; gTasks[task].data[8] = gBattleAnimArgs[3]; REG_BLDALPHA = (gBattleAnimArgs[1] << 8) | gBattleAnimArgs[0]; gTasks[task].func = sub_80796F8; } void sub_80796F8(u8 taskId) { struct Task *task = &gTasks[taskId]; if (++task->data[0] > task->data[1]) { task->data[0] = 0; if (++task->data[2] & 1) { if (task->data[3] != task->data[7]) task->data[3] += task->data[5]; } else { if (task->data[4] != task->data[8]) task->data[4] += task->data[6]; } REG_BLDALPHA = (task->data[4] << 8) | task->data[3]; if (task->data[3] == task->data[7] && task->data[4] == task->data[8]) { DestroyAnimVisualTask(taskId); return; } } } // Linearly blends a mon's sprite colors with a target color with increasing // strength, and then blends out to the original color. // arg 0: anim bank // arg 1: blend color // arg 2: target blend coefficient // arg 3: initial delay // arg 4: number of times to blend in and out void AnimTask_BlendMonInAndOut(u8 task) { u8 spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[0]); if (spriteId == 0xff) { DestroyAnimVisualTask(task); return; } gTasks[task].data[0] = (gSprites[spriteId].oam.paletteNum * 0x10) + 0x101; AnimTask_BlendMonInAndOutSetup(&gTasks[task]); } void AnimTask_BlendMonInAndOutSetup(struct Task *task) { task->data[1] = gBattleAnimArgs[1]; task->data[2] = 0; task->data[3] = gBattleAnimArgs[2]; task->data[4] = 0; task->data[5] = gBattleAnimArgs[3]; task->data[6] = 0; task->data[7] = gBattleAnimArgs[4]; task->func = AnimTask_BlendMonInAndOutStep; } void AnimTask_BlendMonInAndOutStep(u8 taskId) { struct Task *task = &gTasks[taskId]; if (++task->data[4] >= task->data[5]) { task->data[4] = 0; if (!task->data[6]) { task->data[2]++; BlendPalette(task->data[0], 15, task->data[2], task->data[1]); if (task->data[2] == task->data[3]) task->data[6] = 1; } else { task->data[2]--; BlendPalette(task->data[0], 15, task->data[2], task->data[1]); if (!task->data[2]) { if (--task->data[7]) { task->data[4] = 0; task->data[6] = 0; } else { DestroyAnimVisualTask(taskId); return; } } } } } void sub_80798AC(u8 task) { u8 palette = IndexOfSpritePaletteTag(gBattleAnimArgs[0]); if (palette == 0xff) { DestroyAnimVisualTask(task); return; } gTasks[task].data[0] = (palette * 0x10) + 0x101; AnimTask_BlendMonInAndOutSetup(&gTasks[task]); } void PrepareAffineAnimInTaskData(struct Task *task, u8 a2, const void *a3) { task->data[7] = 0; task->data[8] = 0; task->data[9] = 0; task->data[15] = a2; task->data[10] = 0x100; task->data[11] = 0x100; task->data[12] = 0; sub_8079BF4(&task->data[13], &task->data[14], a3); PrepareBattlerSpriteForRotScale(a2, 0); } bool8 RunAffineAnimFromTaskData(struct Task *task) { gUnknown_0202F7D4 = sub_8079BFC(task->data[13], task->data[14]) + (task->data[7] << 3); switch (gUnknown_0202F7D4->type) { default: if (!gUnknown_0202F7D4->frame.duration) { task->data[10] = gUnknown_0202F7D4->frame.xScale; task->data[11] = gUnknown_0202F7D4->frame.yScale; task->data[12] = gUnknown_0202F7D4->frame.rotation; task->data[7]++; gUnknown_0202F7D4++; } task->data[10] += gUnknown_0202F7D4->frame.xScale; task->data[11] += gUnknown_0202F7D4->frame.yScale; task->data[12] += gUnknown_0202F7D4->frame.rotation; obj_id_set_rotscale(task->data[15], task->data[10], task->data[11], task->data[12]); sub_8079A64(task->data[15]); if (++task->data[8] >= gUnknown_0202F7D4->frame.duration) { task->data[8] = 0; task->data[7]++; } break; case AFFINEANIMCMDTYPE_JUMP: task->data[7] = gUnknown_0202F7D4->jump.target; break; case AFFINEANIMCMDTYPE_LOOP: if (gUnknown_0202F7D4->loop.count) { if (task->data[9]) { if (!--task->data[9]) { task->data[7]++; break; } } else { task->data[9] = gUnknown_0202F7D4->loop.count; } if (!task->data[7]) { break; } for (;;) { task->data[7]--; gUnknown_0202F7D4--; if (gUnknown_0202F7D4->type == AFFINEANIMCMDTYPE_LOOP) { task->data[7]++; return TRUE; } if (!task->data[7]) return TRUE; } } task->data[7]++; break; case 0x7fff: gSprites[task->data[15]].y2 = 0; sub_8078F40(task->data[15]); return FALSE; } return TRUE; } void sub_8079A64(u8 sprite) { int var = 0x40 - sub_8079B10(sprite) * 2; u16 matrix = gSprites[sprite].oam.matrixNum; int var2 = (var << 8) / gOamMatrices[matrix].d; if (var2 > 0x80) var2 = 0x80; gSprites[sprite].y2 = (var - var2) / 2; } void sub_8079AB8(u8 sprite, u8 sprite2) { int var = 0x40 - sub_8079B10(sprite2) * 2; u16 matrix = gSprites[sprite].oam.matrixNum; int var2 = (var << 8) / gOamMatrices[matrix].d; if (var2 > 0x80) var2 = 0x80; gSprites[sprite].y2 = (var - var2) / 2; } u16 sub_8079B10(u8 sprite) { struct BattleSpriteInfo *transform; u8 slot = gSprites[sprite].data[0]; u16 species; u16 i; for (i = 0; i < (sizeof(gBattleMonSprites) / sizeof(u8)); i++) { if (gBattleMonSprites[i] == sprite) { if (IsContest()) { species = gContestResources__moveAnim.species; return gMonBackPicCoords[species].y_offset; } else { if (!GetBattlerSide(i)) { transform = &gBattleSpriteInfo[slot]; if (!transform->transformedSpecies) species = GetMonData(&gPlayerParty[gBattleMonPartyPositions[i]], MON_DATA_SPECIES); else species = transform->transformedSpecies; return gMonBackPicCoords[species].y_offset; } else { transform = &gBattleSpriteInfo[slot]; if (!transform->transformedSpecies) species = GetMonData(&gEnemyParty[gBattleMonPartyPositions[i]], MON_DATA_SPECIES); else species = transform->transformedSpecies; return gMonFrontPicCoords[species].y_offset; } } } } return 0x40; } void sub_8079BF4(s16 *bottom, s16 *top, const void *ptr) { *bottom = ((intptr_t) ptr) & 0xffff; *top = (((intptr_t) ptr) >> 16) & 0xffff; } void *sub_8079BFC(s16 bottom, s16 top) { return (void *)((u16)bottom | ((u16)top << 16)); } // possible new file void sub_8079C08(struct Task *task, u8 a2, s16 a3, s16 a4, s16 a5, s16 a6, u16 a7) { task->data[8] = a7; task->data[15] = a2; // spriteId task->data[9] = a3; task->data[10] = a4; task->data[13] = a5; task->data[14] = a6; task->data[11] = (a5 - a3) / a7; task->data[12] = (a6 - a4) / a7; } u8 sub_8079C74(struct Task *task) { if (!task->data[8]) return 0; if (--task->data[8] != 0) { task->data[9] += task->data[11]; task->data[10] += task->data[12]; } else { task->data[9] = task->data[13]; task->data[10] = task->data[14]; } obj_id_set_rotscale(task->data[15], task->data[9], task->data[10], 0); if (task->data[8]) sub_8079A64(task->data[15]); else gSprites[task->data[15]].y2 = 0; return task->data[8]; } void sub_8079CEC(u8 task) { u16 v1; if (gAnimFriendship <= 30) v1 = 0; else if (gAnimFriendship <= 100) v1 = 1; else if (gAnimFriendship <= 200) v1 = 2; else v1 = 3; gBattleAnimArgs[7] = v1; DestroyAnimVisualTask(task); } void unref_sub_8079D20(u8 priority) { if (IsAnimBankSpriteVisible(gBattleAnimTarget)) gSprites[gBattleMonSprites[gBattleAnimTarget]].oam.priority = priority; if (IsAnimBankSpriteVisible(gBattleAnimAttacker)) gSprites[gBattleMonSprites[gBattleAnimAttacker]].oam.priority = priority; if (IsAnimBankSpriteVisible(gBattleAnimTarget ^ 2)) gSprites[gBattleMonSprites[gBattleAnimTarget ^ 2]].oam.priority = priority; if (IsAnimBankSpriteVisible(gBattleAnimAttacker ^ 2)) gSprites[gBattleMonSprites[gBattleAnimAttacker ^ 2]].oam.priority = priority; } void UpdateBattlerSpritePriorities() { int i; for (i = 0; i < gBattlersCount; i++) { if (IsAnimBankSpriteVisible(i)) { gSprites[gBattleMonSprites[i]].subpriority = GetBattlerSubpriority(i); gSprites[gBattleMonSprites[i]].oam.priority = 2; } } } u8 GetBattlerSubpriority(u8 bank) { u8 identity; u8 ret; if (IsContest()) { if (bank == ANIM_BATTLER_ATK_PARTNER) return 30; else return 40; } else { identity = GetBattlerPosition(bank); if (identity == B_POSITION_PLAYER_LEFT) ret = 30; else if (identity == B_POSITION_PLAYER_RIGHT) ret = 20; else if (identity == B_POSITION_OPPONENT_LEFT) ret = 40; else ret = 50; } return ret; } u8 GetBattlerSpriteBGPriority(u8 slot) { u8 status = GetBattlerPosition(slot); if (IsContest()) return 2; if (status == 0 || status == 3) return BG2CNT.priority; else return BG1CNT.priority; } u8 GetBattlerPosition_permutated(u8 slot) { u8 status; if (!IsContest()) { status = GetBattlerPosition(slot); if (status == 0 || status == 3) return 2; else return 1; } return 1; } u8 sub_8079F44(u16 species, bool8 isBackpic, u8 a3, s16 a4, s16 a5, u8 a6, u32 a7, u32 a8) { u8 sprite; u16 sheet = LoadSpriteSheet(&gUnknown_0837F5E0[a3]); u16 palette = AllocSpritePalette(gSpriteTemplate_837F5B0[a3].paletteTag); if (!isBackpic) { LoadCompressedPalette(GetMonSpritePalFromOtIdPersonality(species, a8, a7), (palette * 0x10) + 0x100, 0x20); LoadSpecialPokePic( &gMonFrontPicTable[species], gMonFrontPicCoords[species].coords, gMonFrontPicCoords[species].y_offset, (void *)EWRAM, (void *)EWRAM, species, a7, 1 ); } else { LoadCompressedPalette(GetMonSpritePalFromOtIdPersonality(species, a8, a7), (palette * 0x10) + 0x100, 0x20); LoadSpecialPokePic( &gMonBackPicTable[species], gMonBackPicCoords[species].coords, gMonBackPicCoords[species].y_offset, (void *)EWRAM, (void *)EWRAM, species, a7, 0 ); } DmaCopy32Defvars(3, (void *)EWRAM, (void *)(OBJ_VRAM0 + (sheet * 0x20)), 0x800); if (!isBackpic) sprite = CreateSprite(&gSpriteTemplate_837F5B0[a3], a4, a5 + gMonFrontPicCoords[species].y_offset, a6); else sprite = CreateSprite(&gSpriteTemplate_837F5B0[a3], a4, a5 + gMonBackPicCoords[species].y_offset, a6); if (IsContest()) { gSprites[sprite].affineAnims = gAffineAnims_BattleSpriteContest; StartSpriteAffineAnim(&gSprites[sprite], 0); } return sprite; } void DestroySpriteAndFreeResources_(struct Sprite *sprite) { DestroySpriteAndFreeResources(sprite); } s16 GetBattlerSpriteCoordAttr(u8 slot, u8 a2) { u16 species; u32 personality; u16 letter; u16 var; int ret; const struct MonCoords *coords; struct BattleSpriteInfo *transform; if (IsContest()) { if (gContestResources__moveAnim.hasTargetAnim) { species = gContestResources__moveAnim.targetSpecies; personality = gContestResources__moveAnim.targetPersonality; } else { species = gContestResources__moveAnim.species; personality = gContestResources__moveAnim.personality; } if (species == SPECIES_UNOWN) { letter = GET_UNOWN_LETTER(personality); if (!letter) var = SPECIES_UNOWN; else var = letter + SPECIES_UNOWN_B - 1; coords = &gMonBackPicCoords[var]; } else if (species == SPECIES_CASTFORM) { coords = &gCastformFrontSpriteCoords[gBattleMonForms[slot]]; } else if (species <= SPECIES_EGG) { coords = &gMonBackPicCoords[species]; } else { coords = &gMonBackPicCoords[0]; } } else { if (!GetBattlerSide(slot)) { transform = &gBattleSpriteInfo[slot]; if (!transform->transformedSpecies) { species = GetMonData(&gPlayerParty[gBattleMonPartyPositions[slot]], MON_DATA_SPECIES); personality = GetMonData(&gPlayerParty[gBattleMonPartyPositions[slot]], MON_DATA_PERSONALITY); } else { species = transform->transformedSpecies; personality = gTransformPersonalities[slot]; } if (species == SPECIES_UNOWN) { letter = GET_UNOWN_LETTER(personality); if (!letter) var = SPECIES_UNOWN; else var = letter + SPECIES_UNOWN_B - 1; coords = &gMonBackPicCoords[var]; } else if (species > SPECIES_EGG) { coords = &gMonBackPicCoords[0]; } else { coords = &gMonBackPicCoords[species]; } } else { transform = &gBattleSpriteInfo[slot]; if (!transform->transformedSpecies) { species = GetMonData(&gEnemyParty[gBattleMonPartyPositions[slot]], MON_DATA_SPECIES); personality = GetMonData(&gEnemyParty[gBattleMonPartyPositions[slot]], MON_DATA_PERSONALITY); } else { species = transform->transformedSpecies; personality = gTransformPersonalities[slot]; } if (species == SPECIES_UNOWN) { letter = GET_UNOWN_LETTER(personality); if (!letter) var = SPECIES_UNOWN; else var = letter + SPECIES_UNOWN_B - 1; coords = &gMonFrontPicCoords[var]; } else if (species == SPECIES_CASTFORM) { coords = &gCastformFrontSpriteCoords[gBattleMonForms[slot]]; } else if (species > SPECIES_EGG) { coords = &gMonFrontPicCoords[0]; } else { coords = &gMonFrontPicCoords[species]; } } } switch (a2) { case 0: return (coords->coords & 0xf) * 8; case 1: return (coords->coords >> 4) * 8; case 4: return GetBattlerSpriteCoord(slot, 2) - ((coords->coords >> 4) * 4); case 5: return GetBattlerSpriteCoord(slot, 2) + ((coords->coords >> 4) * 4); case 2: return GetBattlerSpriteCoord(slot, 3) - ((coords->coords & 0xf) * 4); case 3: return GetBattlerSpriteCoord(slot, 3) + ((coords->coords & 0xf) * 4); case 6: ret = GetBattlerSpriteCoord(slot, 1) + 0x1f; return ret - coords->y_offset; default: return 0; } } void SetAverageBattlerPositions(u8 slot, bool8 a2, s16 *x, s16 *y) { u8 v1, v2; s16 v3, v4; s16 v5, v6; if (!a2) { v1 = 0; v2 = 1; } else { v1 = 2; v2 = 3; } v3 = GetBattlerSpriteCoord(slot, v1); v4 = GetBattlerSpriteCoord(slot, v2); if (IsDoubleBattle() && !IsContest()) { v5 = GetBattlerSpriteCoord(slot ^ 2, v1); v6 = GetBattlerSpriteCoord(slot ^ 2, v2); } else { v5 = v3; v6 = v4; } *x = (v3 + v5) / 2; *y = (v4 + v6) / 2; } u8 sub_807A4A0(int bank, u8 sprite, int species) { u8 new_sprite = CreateInvisibleSpriteWithCallback(SpriteCallbackDummy); gSprites[new_sprite] = gSprites[sprite]; gSprites[new_sprite].usingSheet = TRUE; gSprites[new_sprite].oam.priority = 0; gSprites[new_sprite].oam.objMode = 2; gSprites[new_sprite].oam.tileNum = gSprites[sprite].oam.tileNum; gSprites[new_sprite].callback = SpriteCallbackDummy; return new_sprite; } // unused_orb void sub_807A544(struct Sprite *sprite) { sub_8078650(sprite); if (GetBattlerSide(gBattleAnimAttacker)) { sprite->x -= gBattleAnimArgs[0]; gBattleAnimArgs[3] = -gBattleAnimArgs[3]; sprite->hFlip = TRUE; } else { sprite->x += gBattleAnimArgs[0]; } sprite->y += gBattleAnimArgs[1]; sprite->data[0] = gBattleAnimArgs[2]; sprite->data[1] = gBattleAnimArgs[3]; sprite->data[3] = gBattleAnimArgs[4]; sprite->data[5] = gBattleAnimArgs[5]; StoreSpriteCallbackInData(sprite, DestroySpriteAndMatrix); sprite->callback = sub_8078504; } void sub_807A5C4(struct Sprite *sprite) { if (GetBattlerSide(gBattleAnimAttacker)) { sprite->x -= gBattleAnimArgs[0]; gBattleAnimArgs[3] *= -1; } else { sprite->x += gBattleAnimArgs[0]; } sprite->y += gBattleAnimArgs[1]; sprite->data[0] = gBattleAnimArgs[2]; sprite->data[1] = gBattleAnimArgs[3]; sprite->data[3] = gBattleAnimArgs[4]; sprite->data[5] = gBattleAnimArgs[5]; StartSpriteAnim(sprite, gBattleAnimArgs[6]); StoreSpriteCallbackInData(sprite, DestroySpriteAndMatrix); sprite->callback = sub_8078504; } // file_2 void sub_807A63C(struct Sprite *sprite) { sub_8078650(sprite); if (GetBattlerSide(gBattleAnimAttacker)) sprite->x -= gBattleAnimArgs[0]; else sprite->x += gBattleAnimArgs[0]; sprite->y += gBattleAnimArgs[1]; sprite->callback = sub_8078600; StoreSpriteCallbackInData(sprite, DestroyAnimSprite); } // file_3 (punch effect?) void sub_807A69C(u8 taskId) { u16 src; u16 dest; struct Task *task = &gTasks[taskId]; task->data[0] = GetAnimBattlerSpriteId(0); task->data[1] = (GetBattlerSide(gBattleAnimAttacker)) ? -8 : 8; task->data[2] = 0; task->data[3] = 0; gSprites[task->data[0]].x2 -= task->data[0]; task->data[4] = AllocSpritePalette(10097); task->data[5] = 0; dest = (task->data[4] + 0x10) * 0x10; src = (gSprites[task->data[0]].oam.paletteNum + 0x10) * 0x10; task->data[6] = GetBattlerSubpriority(gBattleAnimAttacker); if (task->data[6] == 20 || task->data[6] == 40) task->data[6] = 2; else task->data[6] = 3; CpuCopy32(&gPlttBufferUnfaded[src], &gPlttBufferFaded[dest], 0x20); BlendPalette(dest, 16, gBattleAnimArgs[1], gBattleAnimArgs[0]); task->func = sub_807A784; } void sub_807A784(u8 taskId) { struct Task *task = &gTasks[taskId]; switch (task->data[2]) { case 0: sub_807A850(task, taskId); gSprites[task->data[0]].x2 += task->data[1]; if (++task->data[3] == 5) { task->data[3]--; task->data[2]++; } break; case 1: sub_807A850(task, taskId); gSprites[task->data[0]].x2 -= task->data[1]; if (--task->data[3] == 0) { gSprites[task->data[0]].x2 = 0; task->data[2]++; } break; case 2: if (!task->data[5]) { FreeSpritePaletteByTag(10097); DestroyAnimVisualTask(taskId); } break; } } void sub_807A850(struct Task *task, u8 taskId) { s16 sprite = duplicate_obj_of_side_rel2move_in_transparent_mode(0); if (sprite >= 0) { gSprites[sprite].oam.priority = task->data[6]; gSprites[sprite].oam.paletteNum = task->data[4]; gSprites[sprite].data[0] = 8; gSprites[sprite].data[1] = taskId; gSprites[sprite].data[2] = sprite; gSprites[sprite].x2 = gSprites[task->data[0]].x2; gSprites[sprite].callback = sub_807A8D4; task->data[5]++; } } void sub_807A8D4(struct Sprite *sprite) { if (--sprite->data[0] == 0) { gTasks[sprite->data[1]].data[5]--; obj_delete_but_dont_free_vram(sprite); } } // file_4 void sub_807A908(struct Sprite *sprite) { sprite->x = GetBattlerSpriteCoord(gBattleAnimAttacker, 2); sprite->y = GetBattlerSpriteCoord(gBattleAnimAttacker, 3); if (!GetBattlerSide(gBattleAnimAttacker)) sprite->data[0] = 5; else sprite->data[0] = -10; sprite->data[1] = -40; sprite->callback = sub_807A960; } void sub_807A960(struct Sprite *sprite) { sprite->data[2] += sprite->data[0]; sprite->data[3] += sprite->data[1]; sprite->x2 = sprite->data[2] / 10; sprite->y2 = sprite->data[3] / 10; if (sprite->data[1] < -20) sprite->data[1]++; if (sprite->y + sprite->y2 < -32) DestroyAnimSprite(sprite); } void sub_807A9BC(struct Sprite *sprite) { int x; sprite->data[0] = gBattleAnimArgs[2]; sprite->data[2] = sprite->x + gBattleAnimArgs[4]; sprite->data[4] = sprite->y + gBattleAnimArgs[5]; if (!GetBattlerSide(gBattleAnimTarget)) { x = (u16)gBattleAnimArgs[4] + 30; sprite->x += x; sprite->y = gBattleAnimArgs[5] - 20; } else { x = (u16)gBattleAnimArgs[4] - 30; sprite->x += x; sprite->y = gBattleAnimArgs[5] - 80; } sprite->callback = StartAnimLinearTranslation; StoreSpriteCallbackInData(sprite, DestroyAnimSprite); }