mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-11-18 20:47:40 +01:00
1301 lines
40 KiB
C
1301 lines
40 KiB
C
#include "global.h"
|
|
#include "battle.h"
|
|
#include "battle_controllers.h"
|
|
#include "battle_ai_script_commands.h"
|
|
#include "battle_anim.h"
|
|
#include "constants/battle_anim.h"
|
|
#include "battle_interface.h"
|
|
#include "main.h"
|
|
#include "malloc.h"
|
|
#include "random.h"
|
|
#include "util.h"
|
|
#include "pokemon.h"
|
|
#include "constants/moves.h"
|
|
#include "task.h"
|
|
#include "sprite.h"
|
|
#include "sound.h"
|
|
#include "m4a.h"
|
|
#include "constants/species.h"
|
|
#include "decompress.h"
|
|
#include "data2.h"
|
|
#include "palette.h"
|
|
#include "blend_palette.h"
|
|
#include "contest.h"
|
|
#include "constants/songs.h"
|
|
|
|
extern u8 gBattleBufferA[BATTLE_BANKS_COUNT][0x200];
|
|
extern u8 gActiveBank;
|
|
extern u8 gBattleBanksCount;
|
|
extern u16 gUnknown_020243FC;
|
|
extern u16 gBattlePartyID[BATTLE_BANKS_COUNT];
|
|
extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT];
|
|
extern u8 gBankPositions[BATTLE_BANKS_COUNT];
|
|
extern u8 gBankSpriteIds[BATTLE_BANKS_COUNT];
|
|
extern u8 gHealthBoxesIds[BATTLE_BANKS_COUNT];
|
|
extern u8 gBattleMonForms[BATTLE_BANKS_COUNT];
|
|
extern u32 gTransformedPersonalities[BATTLE_BANKS_COUNT];
|
|
extern struct MusicPlayerInfo gMPlayInfo_SE1;
|
|
extern struct MusicPlayerInfo gMPlayInfo_SE2;
|
|
extern struct MusicPlayerInfo gMPlayInfo_BGM;
|
|
|
|
extern const struct BattleMove gBattleMoves[];
|
|
extern const u8 gUnknown_0831C604[];
|
|
extern const u8 * const gBattleAnims_VariousTable[];
|
|
extern const u8 * const gBattleAnims_Special[];
|
|
extern const struct CompressedSpriteSheet gMonFrontPicTable[];
|
|
extern const struct CompressedSpriteSheet gMonBackPicTable[];
|
|
extern const struct CompressedSpriteSheet gTrainerFrontPicTable[];
|
|
extern const struct CompressedSpriteSheet gTrainerBackPicTable[];
|
|
extern const struct CompressedSpritePalette gTrainerFrontPicPaletteTable[];
|
|
extern const struct CompressedSpritePalette gTrainerBackPicPaletteTable[];
|
|
extern const union AnimCmd* const * const gMonAnimationsSpriteAnimsPtrTable[];
|
|
extern const struct SpriteTemplate gUnknown_08329D98[4];
|
|
extern const struct CompressedSpriteSheet gSpriteSheet_EnemyShadow;
|
|
extern const struct SpriteTemplate gSpriteTemplate_EnemyShadow;
|
|
extern const u8 gEnemyMonElevation[];
|
|
|
|
// graphics
|
|
extern const u32 gUnknown_08C093F0[];
|
|
extern const u32 gSubstituteDollTilemap[];
|
|
extern const u32 gSubstituteDollGfx[];
|
|
extern const u16 gSubstituteDollPal[];
|
|
extern const u8 gUnknown_08C1F1C8[];
|
|
extern const u8 gUnknown_08C1F46C[];
|
|
extern const u8 gUnknown_08C1F5E8[];
|
|
extern const u8 gUnknown_08C1F76C[];
|
|
extern const u8 gUnknown_08C1F8E8[];
|
|
extern const u8 gBlankGfxCompressed[];
|
|
extern const u16 gBattleInterface_BallStatusBarPal[];
|
|
extern const u16 gBattleInterface_BallDisplayPal[];
|
|
|
|
extern u8 sub_80688F8(u8, u8 bank);
|
|
extern u8 pokemon_order_func(u8); // party menu
|
|
extern void sub_81B8C68(void);
|
|
|
|
// this file's functions
|
|
static u8 sub_805D4A8(u16 move);
|
|
static u16 BattlePalaceGetTargetRetValue(void);
|
|
static void sub_805D7EC(struct Sprite *sprite);
|
|
static bool8 ShouldAnimBeDoneRegardlessOfSubsitute(u8 animId);
|
|
static void Task_ClearBitWhenBattleTableAnimDone(u8 taskId);
|
|
static void Task_ClearBitWhenSpecialAnimDone(u8 taskId);
|
|
static void ClearSpritesBankHealthboxAnimData(void);
|
|
|
|
// const rom data
|
|
static const struct CompressedSpriteSheet gUnknown_0832C0D0 =
|
|
{
|
|
gUnknown_08C1F1C8, 0x1000, TAG_HEALTHBOX_PLAYER1_TILE
|
|
};
|
|
|
|
static const struct CompressedSpriteSheet gUnknown_0832C0D8 =
|
|
{
|
|
gUnknown_08C1F46C, 0x1000, TAG_HEALTHBOX_OPPONENT1_TILE
|
|
};
|
|
|
|
static const struct CompressedSpriteSheet gUnknown_0832C0E0[2] =
|
|
{
|
|
{gUnknown_08C1F5E8, 0x800, TAG_HEALTHBOX_PLAYER1_TILE},
|
|
{gUnknown_08C1F5E8, 0x800, TAG_HEALTHBOX_PLAYER2_TILE}
|
|
};
|
|
|
|
static const struct CompressedSpriteSheet gUnknown_0832C0F0[2] =
|
|
{
|
|
{gUnknown_08C1F76C, 0x800, TAG_HEALTHBOX_OPPONENT1_TILE},
|
|
{gUnknown_08C1F76C, 0x800, TAG_HEALTHBOX_OPPONENT2_TILE}
|
|
};
|
|
|
|
static const struct CompressedSpriteSheet gUnknown_0832C100 =
|
|
{
|
|
gUnknown_08C1F8E8, 0x1000, TAG_HEALTHBOX_SAFARI_TILE
|
|
};
|
|
|
|
static const struct CompressedSpriteSheet gUnknown_0832C108[BATTLE_BANKS_COUNT] =
|
|
{
|
|
{gBlankGfxCompressed, 0x0100, 0xd704},
|
|
{gBlankGfxCompressed, 0x0120, 0xd705},
|
|
{gBlankGfxCompressed, 0x0100, 0xd706},
|
|
{gBlankGfxCompressed, 0x0120, 0xd707}
|
|
};
|
|
|
|
static const struct SpritePalette gUnknown_0832C128[2] =
|
|
{
|
|
{gBattleInterface_BallStatusBarPal, TAG_HEALTHBOX_PAL},
|
|
{gBattleInterface_BallDisplayPal, 0xd704}
|
|
};
|
|
|
|
// code
|
|
void AllocateBattleSpritesData(void)
|
|
{
|
|
gBattleSpritesDataPtr = AllocZeroed(sizeof(struct BattleSpriteData));
|
|
gBattleSpritesDataPtr->bankData = AllocZeroed(sizeof(struct BattleSpriteInfo) * BATTLE_BANKS_COUNT);
|
|
gBattleSpritesDataPtr->healthBoxesData = AllocZeroed(sizeof(struct BattleHealthboxInfo) * BATTLE_BANKS_COUNT);
|
|
gBattleSpritesDataPtr->animationData = AllocZeroed(sizeof(struct BattleAnimationInfo));
|
|
gBattleSpritesDataPtr->battleBars = AllocZeroed(sizeof(struct BattleBarInfo) * BATTLE_BANKS_COUNT);
|
|
}
|
|
|
|
void FreeBattleSpritesData(void)
|
|
{
|
|
if (gBattleSpritesDataPtr == NULL)
|
|
return;
|
|
|
|
FREE_AND_SET_NULL(gBattleSpritesDataPtr->battleBars);
|
|
FREE_AND_SET_NULL(gBattleSpritesDataPtr->animationData);
|
|
FREE_AND_SET_NULL(gBattleSpritesDataPtr->healthBoxesData);
|
|
FREE_AND_SET_NULL(gBattleSpritesDataPtr->bankData);
|
|
FREE_AND_SET_NULL(gBattleSpritesDataPtr);
|
|
}
|
|
|
|
u16 ChooseMoveAndTargetInBattlePalace(void)
|
|
{
|
|
s32 i, var1, var2;
|
|
s32 chosenMoveId = -1;
|
|
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleBufferA[gActiveBank][4]);
|
|
u8 unusableMovesBits = CheckMoveLimitations(gActiveBank, 0, 0xFF);
|
|
s32 percent = Random() % 100;
|
|
|
|
i = (gBattleStruct->field_92 & gBitTable[gActiveBank]) ? 2 : 0;
|
|
var2 = i;
|
|
var1 = i + 2;
|
|
|
|
for (; i < var1; i++)
|
|
{
|
|
if (gUnknown_0831C494[GetNatureFromPersonality(gBattleMons[gActiveBank].personality)][i] > percent)
|
|
break;
|
|
}
|
|
|
|
percent = i - var2;
|
|
if (i == var1)
|
|
percent = 2;
|
|
|
|
for (var2 = 0, i = 0; i < 4; i++)
|
|
{
|
|
if (moveInfo->moves[i] == MOVE_NONE)
|
|
break;
|
|
if (percent == sub_805D4A8(moveInfo->moves[i]) && moveInfo->currentPp[i] != 0)
|
|
var2 |= gBitTable[i];
|
|
}
|
|
|
|
if (var2 != 0)
|
|
{
|
|
gBattleStruct->field_92 &= 0xF;
|
|
gBattleStruct->field_92 |= (var2 << 4);
|
|
BattleAI_SetupAIData(var2);
|
|
chosenMoveId = BattleAI_ChooseMoveOrAction();
|
|
}
|
|
|
|
if (chosenMoveId == -1)
|
|
{
|
|
if (unusableMovesBits != 0xF)
|
|
{
|
|
var1 = 0, var2 = 0;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (sub_805D4A8(moveInfo->moves[i]) == 0 && !(gBitTable[i] & unusableMovesBits))
|
|
var1 += 0x1;
|
|
if (sub_805D4A8(moveInfo->moves[i]) == 1 && !(gBitTable[i] & unusableMovesBits))
|
|
var1 += 0x10;
|
|
if (sub_805D4A8(moveInfo->moves[i]) == 2 && !(gBitTable[i] & unusableMovesBits))
|
|
var1 += 0x100;
|
|
}
|
|
|
|
if ((var1 & 0xF) > 1)
|
|
var2++;
|
|
if ((var1 & 0xF0) > 0x1F)
|
|
var2++;
|
|
if ((var1 & 0xF0) > 0x1FF)
|
|
var2++;
|
|
|
|
if (var2 > 1 || var2 == 0)
|
|
{
|
|
do
|
|
{
|
|
i = Random() % 4;
|
|
if (!(gBitTable[i] & unusableMovesBits))
|
|
chosenMoveId = i;
|
|
} while (chosenMoveId == -1);
|
|
}
|
|
else
|
|
{
|
|
if ((var1 & 0xF) > 1)
|
|
var2 = 0;
|
|
if ((var1 & 0xF0) > 0x1F)
|
|
var2 = 1;
|
|
if ((var1 & 0xF0) > 0x1FF)
|
|
var2 = 2;
|
|
|
|
do
|
|
{
|
|
i = Random() % 4;
|
|
if (!(gBitTable[i] & unusableMovesBits) && var2 == sub_805D4A8(moveInfo->moves[i]))
|
|
chosenMoveId = i;
|
|
} while (chosenMoveId == -1);
|
|
}
|
|
|
|
if (Random() % 100 > 49)
|
|
{
|
|
gProtectStructs[gActiveBank].flag_x10 = 1;
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gProtectStructs[gActiveBank].flag_x10 = 1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (moveInfo->moves[chosenMoveId] == MOVE_CURSE)
|
|
{
|
|
if (moveInfo->monType1 != TYPE_GHOST && moveInfo->monType2 != TYPE_GHOST)
|
|
var1 = MOVE_TARGET_x10;
|
|
else
|
|
var1 = MOVE_TARGET_SELECTED;
|
|
}
|
|
else
|
|
{
|
|
var1 = gBattleMoves[moveInfo->moves[chosenMoveId]].target;
|
|
}
|
|
|
|
if (var1 & MOVE_TARGET_x10)
|
|
chosenMoveId |= (gActiveBank << 8);
|
|
else if (var1 == MOVE_TARGET_SELECTED)
|
|
chosenMoveId |= (BattlePalaceGetTargetRetValue());
|
|
else
|
|
chosenMoveId |= (GetBankByPosition((GetBankPosition(gActiveBank) & BIT_SIDE) ^ BIT_SIDE) << 8);
|
|
|
|
return chosenMoveId;
|
|
}
|
|
|
|
static u8 sub_805D4A8(u16 move)
|
|
{
|
|
switch (gBattleMoves[move].target)
|
|
{
|
|
case MOVE_TARGET_SELECTED:
|
|
case MOVE_TARGET_USER:
|
|
case MOVE_TARGET_RANDOM:
|
|
case MOVE_TARGET_BOTH:
|
|
case MOVE_TARGET_FOES_AND_ALLY:
|
|
if (gBattleMoves[move].power == 0)
|
|
return 2;
|
|
else
|
|
return 0;
|
|
break;
|
|
case MOVE_TARGET_DEPENDS:
|
|
case MOVE_TARGET_OPPONENTS_FIELD:
|
|
return 2;
|
|
case MOVE_TARGET_x10:
|
|
return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static u16 BattlePalaceGetTargetRetValue(void)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
{
|
|
u8 opposing1, opposing2;
|
|
|
|
if (GetBankSide(gActiveBank) == SIDE_PLAYER)
|
|
{
|
|
opposing1 = GetBankByPosition(B_POSITION_OPPONENT_LEFT);
|
|
opposing2 = GetBankByPosition(B_POSITION_OPPONENT_RIGHT);
|
|
}
|
|
else
|
|
{
|
|
opposing1 = GetBankByPosition(B_POSITION_PLAYER_LEFT);
|
|
opposing2 = GetBankByPosition(B_POSITION_PLAYER_RIGHT);
|
|
}
|
|
|
|
if (gBattleMons[opposing1].hp == gBattleMons[opposing2].hp)
|
|
return (((gActiveBank & BIT_SIDE) ^ BIT_SIDE) + (Random() & 2)) << 8;
|
|
|
|
switch (gUnknown_0831C604[GetNatureFromPersonality(gBattleMons[gActiveBank].personality)])
|
|
{
|
|
case 0:
|
|
if (gBattleMons[opposing1].hp > gBattleMons[opposing2].hp)
|
|
return opposing1 << 8;
|
|
else
|
|
return opposing2 << 8;
|
|
case 1:
|
|
if (gBattleMons[opposing1].hp < gBattleMons[opposing2].hp)
|
|
return opposing1 << 8;
|
|
else
|
|
return opposing2 << 8;
|
|
case 2:
|
|
return (((gActiveBank & BIT_SIDE) ^ BIT_SIDE) + (Random() & 2)) << 8;
|
|
}
|
|
}
|
|
|
|
return (gActiveBank ^ BIT_SIDE) << 8;
|
|
}
|
|
|
|
void sub_805D714(struct Sprite *sprite)
|
|
{
|
|
u8 spriteId = sprite->data[1];
|
|
|
|
if (!gSprites[spriteId].affineAnimEnded)
|
|
return;
|
|
if (gSprites[spriteId].invisible)
|
|
return;
|
|
|
|
if (gSprites[spriteId].animPaused)
|
|
{
|
|
gSprites[spriteId].animPaused = 0;
|
|
}
|
|
else
|
|
{
|
|
if (gSprites[spriteId].animEnded)
|
|
sprite->callback = SpriteCallbackDummy;
|
|
}
|
|
}
|
|
|
|
void sub_805D770(struct Sprite *sprite, bool8 arg1)
|
|
{
|
|
sprite->animPaused = 1;
|
|
sprite->callback = SpriteCallbackDummy;
|
|
|
|
if (!arg1)
|
|
StartSpriteAffineAnim(sprite, 1);
|
|
else
|
|
StartSpriteAffineAnim(sprite, 1);
|
|
|
|
AnimateSprite(sprite);
|
|
}
|
|
|
|
void sub_805D7AC(struct Sprite *sprite)
|
|
{
|
|
if (!(gUnknown_020243FC & 1))
|
|
{
|
|
sprite->pos2.x += sprite->data[0];
|
|
if (sprite->pos2.x == 0)
|
|
{
|
|
if (sprite->pos2.y != 0)
|
|
sprite->callback = sub_805D7EC;
|
|
else
|
|
sprite->callback = SpriteCallbackDummy;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sub_805D7EC(struct Sprite *sprite)
|
|
{
|
|
sprite->pos2.y -= 2;
|
|
if (sprite->pos2.y == 0)
|
|
sprite->callback = SpriteCallbackDummy;
|
|
}
|
|
|
|
void InitAndLaunchChosenStatusAnimation(bool8 isStatus2, u32 status)
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBank].statusAnimActive = 1;
|
|
if (!isStatus2)
|
|
{
|
|
if (status == STATUS1_FREEZE)
|
|
LaunchStatusAnimation(gActiveBank, B_ANIM_STATUS_FRZ);
|
|
else if (status == STATUS1_POISON || status & STATUS1_TOXIC_POISON)
|
|
LaunchStatusAnimation(gActiveBank, B_ANIM_STATUS_PSN);
|
|
else if (status == STATUS1_BURN)
|
|
LaunchStatusAnimation(gActiveBank, B_ANIM_STATUS_BRN);
|
|
else if (status & STATUS1_SLEEP)
|
|
LaunchStatusAnimation(gActiveBank, B_ANIM_STATUS_SLP);
|
|
else if (status == STATUS1_PARALYSIS)
|
|
LaunchStatusAnimation(gActiveBank, B_ANIM_STATUS_PRZ);
|
|
else // no animation
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBank].statusAnimActive = 0;
|
|
}
|
|
else
|
|
{
|
|
if (status & STATUS2_INFATUATION)
|
|
LaunchStatusAnimation(gActiveBank, B_ANIM_STATUS_INFATUATION);
|
|
else if (status & STATUS2_CONFUSION)
|
|
LaunchStatusAnimation(gActiveBank, B_ANIM_STATUS_CONFUSION);
|
|
else if (status & STATUS2_CURSED)
|
|
LaunchStatusAnimation(gActiveBank, B_ANIM_STATUS_CURSED);
|
|
else if (status & STATUS2_NIGHTMARE)
|
|
LaunchStatusAnimation(gActiveBank, B_ANIM_STATUS_NIGHTMARE);
|
|
else if (status & STATUS2_WRAPPED)
|
|
LaunchStatusAnimation(gActiveBank, B_ANIM_STATUS_WRAPPED); // this animation doesn't actually exist
|
|
else // no animation
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBank].statusAnimActive = 0;
|
|
}
|
|
}
|
|
|
|
#define tBank data[0]
|
|
|
|
bool8 TryHandleLaunchBattleTableAnimation(u8 activeBank, u8 atkBank, u8 defBank, u8 tableId, u16 argument)
|
|
{
|
|
u8 taskId;
|
|
|
|
if (tableId == B_ANIM_CASTFORM_CHANGE && (argument & 0x80))
|
|
{
|
|
gBattleMonForms[activeBank] = (argument & ~(0x80));
|
|
return TRUE;
|
|
}
|
|
if (gBattleSpritesDataPtr->bankData[activeBank].behindSubstitute
|
|
&& !ShouldAnimBeDoneRegardlessOfSubsitute(tableId))
|
|
{
|
|
return TRUE;
|
|
}
|
|
if (gBattleSpritesDataPtr->bankData[activeBank].behindSubstitute
|
|
&& tableId == B_ANIM_SUBSTITUTE_FADE
|
|
&& gSprites[gBankSpriteIds[activeBank]].invisible)
|
|
{
|
|
LoadBattleMonGfxAndAnimate(activeBank, TRUE, gBankSpriteIds[activeBank]);
|
|
ClearBehindSubstituteBit(activeBank);
|
|
return TRUE;
|
|
}
|
|
|
|
gAnimBankAttacker = atkBank;
|
|
gAnimBankTarget = defBank;
|
|
gBattleSpritesDataPtr->animationData->animArg = argument;
|
|
LaunchBattleAnimation(gBattleAnims_VariousTable, tableId, FALSE);
|
|
taskId = CreateTask(Task_ClearBitWhenBattleTableAnimDone, 10);
|
|
gTasks[taskId].tBank = activeBank;
|
|
gBattleSpritesDataPtr->healthBoxesData[gTasks[taskId].tBank].animFromTableActive = 1;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void Task_ClearBitWhenBattleTableAnimDone(u8 taskId)
|
|
{
|
|
gAnimScriptCallback();
|
|
if (!gAnimScriptActive)
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[gTasks[taskId].tBank].animFromTableActive = 0;
|
|
DestroyTask(taskId);
|
|
}
|
|
}
|
|
|
|
#undef tBank
|
|
|
|
static bool8 ShouldAnimBeDoneRegardlessOfSubsitute(u8 animId)
|
|
{
|
|
switch (animId)
|
|
{
|
|
case B_ANIM_SUBSTITUTE_FADE:
|
|
case B_ANIM_RAIN_CONTINUES:
|
|
case B_ANIM_SUN_CONTINUES:
|
|
case B_ANIM_SANDSTORM_CONTINUES:
|
|
case B_ANIM_HAIL_CONTINUES:
|
|
case B_ANIM_SNATCH_MOVE:
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
#define tBank data[0]
|
|
|
|
void InitAndLaunchSpecialAnimation(u8 activeBank, u8 atkBank, u8 defBank, u8 tableId)
|
|
{
|
|
u8 taskId;
|
|
|
|
gAnimBankAttacker = atkBank;
|
|
gAnimBankTarget = defBank;
|
|
LaunchBattleAnimation(gBattleAnims_Special, tableId, FALSE);
|
|
taskId = CreateTask(Task_ClearBitWhenSpecialAnimDone, 10);
|
|
gTasks[taskId].tBank = activeBank;
|
|
gBattleSpritesDataPtr->healthBoxesData[gTasks[taskId].tBank].specialAnimActive = 1;
|
|
}
|
|
|
|
static void Task_ClearBitWhenSpecialAnimDone(u8 taskId)
|
|
{
|
|
gAnimScriptCallback();
|
|
if (!gAnimScriptActive)
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[gTasks[taskId].tBank].specialAnimActive = 0;
|
|
DestroyTask(taskId);
|
|
}
|
|
}
|
|
|
|
#undef tBank
|
|
|
|
// great function to include newly added moves that don't have animation yet
|
|
bool8 IsMoveWithoutAnimation(u16 moveId, u8 animationTurn)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
bool8 mplay_80342A4(u8 bank)
|
|
{
|
|
u8 zero = 0;
|
|
|
|
if (IsSEPlaying())
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[bank].field_8++;
|
|
if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_8 < 30)
|
|
return TRUE;
|
|
|
|
m4aMPlayStop(&gMPlayInfo_SE1);
|
|
m4aMPlayStop(&gMPlayInfo_SE2);
|
|
}
|
|
if (zero == 0)
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[bank].field_8 = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void BattleLoadOpponentMonSpriteGfx(struct Pokemon *mon, u8 bank)
|
|
{
|
|
u32 monsPersonality, currentPersonality, otId;
|
|
u16 species;
|
|
u8 identity;
|
|
u16 paletteOffset;
|
|
const void *lzPaletteData;
|
|
|
|
monsPersonality = GetMonData(mon, MON_DATA_PERSONALITY);
|
|
|
|
if (gBattleSpritesDataPtr->bankData[bank].transformSpecies == SPECIES_NONE)
|
|
{
|
|
species = GetMonData(mon, MON_DATA_SPECIES);
|
|
currentPersonality = monsPersonality;
|
|
}
|
|
else
|
|
{
|
|
species = gBattleSpritesDataPtr->bankData[bank].transformSpecies;
|
|
currentPersonality = gTransformedPersonalities[bank];
|
|
}
|
|
|
|
otId = GetMonData(mon, MON_DATA_OT_ID);
|
|
identity = GetBankPosition(bank);
|
|
HandleLoadSpecialPokePic_DontHandleDeoxys(&gMonFrontPicTable[species],
|
|
gMonSpritesGfxPtr->sprites[identity],
|
|
species, currentPersonality);
|
|
|
|
paletteOffset = 0x100 + bank * 16;
|
|
|
|
if (gBattleSpritesDataPtr->bankData[bank].transformSpecies == SPECIES_NONE)
|
|
lzPaletteData = GetMonFrontSpritePal(mon);
|
|
else
|
|
lzPaletteData = GetFrontSpritePalFromSpeciesAndPersonality(species, otId, monsPersonality);
|
|
|
|
LZDecompressWram(lzPaletteData, gDecompressionBuffer);
|
|
LoadPalette(gDecompressionBuffer, paletteOffset, 0x20);
|
|
LoadPalette(gDecompressionBuffer, 0x80 + bank * 16, 0x20);
|
|
|
|
if (species == SPECIES_CASTFORM)
|
|
{
|
|
paletteOffset = 0x100 + bank * 16;
|
|
LZDecompressWram(lzPaletteData, gBattleStruct->castformPalette[0]);
|
|
LoadPalette(gBattleStruct->castformPalette[gBattleMonForms[bank]], paletteOffset, 0x20);
|
|
}
|
|
|
|
// transform's pink color
|
|
if (gBattleSpritesDataPtr->bankData[bank].transformSpecies != SPECIES_NONE)
|
|
{
|
|
BlendPalette(paletteOffset, 16, 6, 0x7FFF);
|
|
CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, 32);
|
|
}
|
|
}
|
|
|
|
void BattleLoadPlayerMonSpriteGfx(struct Pokemon *mon, u8 bank)
|
|
{
|
|
u32 monsPersonality, currentPersonality, otId;
|
|
u16 species;
|
|
u8 identity;
|
|
u16 paletteOffset;
|
|
const void *lzPaletteData;
|
|
|
|
monsPersonality = GetMonData(mon, MON_DATA_PERSONALITY);
|
|
|
|
if (gBattleSpritesDataPtr->bankData[bank].transformSpecies == SPECIES_NONE)
|
|
{
|
|
species = GetMonData(mon, MON_DATA_SPECIES);
|
|
currentPersonality = monsPersonality;
|
|
}
|
|
else
|
|
{
|
|
species = gBattleSpritesDataPtr->bankData[bank].transformSpecies;
|
|
currentPersonality = gTransformedPersonalities[bank];
|
|
}
|
|
|
|
otId = GetMonData(mon, MON_DATA_OT_ID);
|
|
identity = GetBankPosition(bank);
|
|
|
|
if (sub_80688F8(1, bank) == 1 || gBattleSpritesDataPtr->bankData[bank].transformSpecies != SPECIES_NONE)
|
|
{
|
|
HandleLoadSpecialPokePic_DontHandleDeoxys(&gMonBackPicTable[species],
|
|
gMonSpritesGfxPtr->sprites[identity],
|
|
species, currentPersonality);
|
|
}
|
|
else
|
|
{
|
|
HandleLoadSpecialPokePic(&gMonBackPicTable[species],
|
|
gMonSpritesGfxPtr->sprites[identity],
|
|
species, currentPersonality);
|
|
}
|
|
|
|
paletteOffset = 0x100 + bank * 16;
|
|
|
|
if (gBattleSpritesDataPtr->bankData[bank].transformSpecies == SPECIES_NONE)
|
|
lzPaletteData = GetMonFrontSpritePal(mon);
|
|
else
|
|
lzPaletteData = GetFrontSpritePalFromSpeciesAndPersonality(species, otId, monsPersonality);
|
|
|
|
LZDecompressWram(lzPaletteData, gDecompressionBuffer);
|
|
LoadPalette(gDecompressionBuffer, paletteOffset, 0x20);
|
|
LoadPalette(gDecompressionBuffer, 0x80 + bank * 16, 0x20);
|
|
|
|
if (species == SPECIES_CASTFORM)
|
|
{
|
|
paletteOffset = 0x100 + bank * 16;
|
|
LZDecompressWram(lzPaletteData, gBattleStruct->castformPalette[0]);
|
|
LoadPalette(gBattleStruct->castformPalette[gBattleMonForms[bank]], paletteOffset, 0x20);
|
|
}
|
|
|
|
// transform's pink color
|
|
if (gBattleSpritesDataPtr->bankData[bank].transformSpecies != SPECIES_NONE)
|
|
{
|
|
BlendPalette(paletteOffset, 16, 6, 0x7FFF);
|
|
CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, 32);
|
|
}
|
|
}
|
|
|
|
void nullsub_23(void)
|
|
{
|
|
}
|
|
|
|
void nullsub_24(u16 species)
|
|
{
|
|
}
|
|
|
|
void DecompressTrainerFrontPic(u16 frontPicId, u8 bank)
|
|
{
|
|
u8 identity = GetBankPosition(bank);
|
|
DecompressPicFromTable_2(&gTrainerFrontPicTable[frontPicId],
|
|
gMonSpritesGfxPtr->sprites[identity],
|
|
SPECIES_NONE);
|
|
LoadCompressedObjectPalette(&gTrainerFrontPicPaletteTable[frontPicId]);
|
|
}
|
|
|
|
void DecompressTrainerBackPic(u16 backPicId, u8 bank)
|
|
{
|
|
u8 identity = GetBankPosition(bank);
|
|
DecompressPicFromTable_2(&gTrainerBackPicTable[backPicId],
|
|
gMonSpritesGfxPtr->sprites[identity],
|
|
SPECIES_NONE);
|
|
LoadCompressedPalette(gTrainerBackPicPaletteTable[backPicId].data,
|
|
0x100 + 16 * bank, 0x20);
|
|
}
|
|
|
|
void nullsub_25(u8 arg0)
|
|
{
|
|
}
|
|
|
|
void FreeTrainerFrontPicPalette(u16 frontPicId)
|
|
{
|
|
FreeSpritePaletteByTag(gTrainerFrontPicPaletteTable[frontPicId].tag);
|
|
}
|
|
|
|
void sub_805DFFC(void)
|
|
{
|
|
u8 numberOfBanks = 0;
|
|
u8 i;
|
|
|
|
LoadSpritePalette(&gUnknown_0832C128[0]);
|
|
LoadSpritePalette(&gUnknown_0832C128[1]);
|
|
if (!IsDoubleBattle())
|
|
{
|
|
LoadCompressedObjectPic(&gUnknown_0832C0D0);
|
|
LoadCompressedObjectPic(&gUnknown_0832C0D8);
|
|
numberOfBanks = 2;
|
|
}
|
|
else
|
|
{
|
|
LoadCompressedObjectPic(&gUnknown_0832C0E0[0]);
|
|
LoadCompressedObjectPic(&gUnknown_0832C0E0[1]);
|
|
LoadCompressedObjectPic(&gUnknown_0832C0F0[0]);
|
|
LoadCompressedObjectPic(&gUnknown_0832C0F0[1]);
|
|
numberOfBanks = 4;
|
|
}
|
|
for (i = 0; i < numberOfBanks; i++)
|
|
LoadCompressedObjectPic(&gUnknown_0832C108[gBankPositions[i]]);
|
|
}
|
|
|
|
bool8 BattleLoadAllHealthBoxesGfx(u8 state)
|
|
{
|
|
bool8 retVal = FALSE;
|
|
|
|
if (state != 0)
|
|
{
|
|
if (state == 1)
|
|
{
|
|
LoadSpritePalette(&gUnknown_0832C128[0]);
|
|
LoadSpritePalette(&gUnknown_0832C128[1]);
|
|
}
|
|
else if (!IsDoubleBattle())
|
|
{
|
|
if (state == 2)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
|
|
LoadCompressedObjectPic(&gUnknown_0832C100);
|
|
else
|
|
LoadCompressedObjectPic(&gUnknown_0832C0D0);
|
|
}
|
|
else if (state == 3)
|
|
LoadCompressedObjectPic(&gUnknown_0832C0D8);
|
|
else if (state == 4)
|
|
LoadCompressedObjectPic(&gUnknown_0832C108[gBankPositions[0]]);
|
|
else if (state == 5)
|
|
LoadCompressedObjectPic(&gUnknown_0832C108[gBankPositions[1]]);
|
|
else
|
|
retVal = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (state == 2)
|
|
LoadCompressedObjectPic(&gUnknown_0832C0E0[0]);
|
|
else if (state == 3)
|
|
LoadCompressedObjectPic(&gUnknown_0832C0E0[1]);
|
|
else if (state == 4)
|
|
LoadCompressedObjectPic(&gUnknown_0832C0F0[0]);
|
|
else if (state == 5)
|
|
LoadCompressedObjectPic(&gUnknown_0832C0F0[1]);
|
|
else if (state == 6)
|
|
LoadCompressedObjectPic(&gUnknown_0832C108[gBankPositions[0]]);
|
|
else if (state == 7)
|
|
LoadCompressedObjectPic(&gUnknown_0832C108[gBankPositions[1]]);
|
|
else if (state == 8)
|
|
LoadCompressedObjectPic(&gUnknown_0832C108[gBankPositions[2]]);
|
|
else if (state == 9)
|
|
LoadCompressedObjectPic(&gUnknown_0832C108[gBankPositions[3]]);
|
|
else
|
|
retVal = TRUE;
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
void LoadBattleBarGfx(u8 arg0)
|
|
{
|
|
LZDecompressWram(gUnknown_08C093F0, gMonSpritesGfxPtr->barFontGfx);
|
|
}
|
|
|
|
bool8 BattleInitAllSprites(u8 *state1, u8 *bank)
|
|
{
|
|
bool8 retVal = FALSE;
|
|
|
|
switch (*state1)
|
|
{
|
|
case 0:
|
|
ClearSpritesBankHealthboxAnimData();
|
|
(*state1)++;
|
|
break;
|
|
case 1:
|
|
if (!BattleLoadAllHealthBoxesGfx(*bank))
|
|
{
|
|
(*bank)++;
|
|
}
|
|
else
|
|
{
|
|
*bank = 0;
|
|
(*state1)++;
|
|
}
|
|
break;
|
|
case 2:
|
|
(*state1)++;
|
|
break;
|
|
case 3:
|
|
if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI) && *bank == 0)
|
|
gHealthBoxesIds[*bank] = CreateSafariPlayerHealthboxSprites();
|
|
else
|
|
gHealthBoxesIds[*bank] = CreateBankHealthboxSprites(*bank);
|
|
|
|
(*bank)++;
|
|
if (*bank == gBattleBanksCount)
|
|
{
|
|
*bank = 0;
|
|
(*state1)++;
|
|
}
|
|
break;
|
|
case 4:
|
|
SetBankHealthboxSpritePos(*bank);
|
|
if (gBankPositions[*bank] <= 1)
|
|
DummyBattleInterfaceFunc(gHealthBoxesIds[*bank], FALSE);
|
|
else
|
|
DummyBattleInterfaceFunc(gHealthBoxesIds[*bank], TRUE);
|
|
|
|
(*bank)++;
|
|
if (*bank == gBattleBanksCount)
|
|
{
|
|
*bank = 0;
|
|
(*state1)++;
|
|
}
|
|
break;
|
|
case 5:
|
|
if (GetBankSide(*bank) == SIDE_PLAYER)
|
|
{
|
|
if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI))
|
|
UpdateHealthboxAttribute(gHealthBoxesIds[*bank], &gPlayerParty[gBattlePartyID[*bank]], HEALTHBOX_ALL);
|
|
}
|
|
else
|
|
{
|
|
UpdateHealthboxAttribute(gHealthBoxesIds[*bank], &gEnemyParty[gBattlePartyID[*bank]], HEALTHBOX_ALL);
|
|
}
|
|
SetHealthboxSpriteInvisible(gHealthBoxesIds[*bank]);
|
|
(*bank)++;
|
|
if (*bank == gBattleBanksCount)
|
|
{
|
|
*bank = 0;
|
|
(*state1)++;
|
|
}
|
|
break;
|
|
case 6:
|
|
LoadAndCreateEnemyShadowSprites();
|
|
sub_81B8C68();
|
|
retVal = TRUE;
|
|
break;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
void ClearSpritesHealthboxAnimData(void)
|
|
{
|
|
memset(gBattleSpritesDataPtr->healthBoxesData, 0, sizeof(struct BattleHealthboxInfo) * BATTLE_BANKS_COUNT);
|
|
memset(gBattleSpritesDataPtr->animationData, 0, sizeof(struct BattleAnimationInfo));
|
|
}
|
|
|
|
static void ClearSpritesBankHealthboxAnimData(void)
|
|
{
|
|
ClearSpritesHealthboxAnimData();
|
|
memset(gBattleSpritesDataPtr->bankData, 0, sizeof(struct BattleSpriteInfo) * BATTLE_BANKS_COUNT);
|
|
}
|
|
|
|
void CopyAllBattleSpritesInvisibilities(void)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < gBattleBanksCount; i++)
|
|
gBattleSpritesDataPtr->bankData[i].invisible = gSprites[gBankSpriteIds[i]].invisible;
|
|
}
|
|
|
|
void CopyBattleSpriteInvisibility(u8 bank)
|
|
{
|
|
gBattleSpritesDataPtr->bankData[bank].invisible = gSprites[gBankSpriteIds[bank]].invisible;
|
|
}
|
|
|
|
void HandleSpeciesGfxDataChange(u8 bankAtk, u8 bankDef, bool8 notTransform)
|
|
{
|
|
u16 paletteOffset;
|
|
u32 personalityValue;
|
|
u32 otId;
|
|
u8 identity;
|
|
const u8 *lzPaletteData;
|
|
|
|
if (notTransform)
|
|
{
|
|
StartSpriteAnim(&gSprites[gBankSpriteIds[bankAtk]], gBattleSpritesDataPtr->animationData->animArg);
|
|
paletteOffset = 0x100 + bankAtk * 16;
|
|
LoadPalette(gBattleStruct->castformPalette[gBattleSpritesDataPtr->animationData->animArg], paletteOffset, 32);
|
|
gBattleMonForms[bankAtk] = gBattleSpritesDataPtr->animationData->animArg;
|
|
if (gBattleSpritesDataPtr->bankData[bankAtk].transformSpecies != SPECIES_NONE)
|
|
{
|
|
BlendPalette(paletteOffset, 16, 6, 0x7FFF);
|
|
CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, 32);
|
|
}
|
|
gSprites[gBankSpriteIds[bankAtk]].pos1.y = GetBankSpriteDefault_Y(bankAtk);
|
|
}
|
|
else
|
|
{
|
|
const void *src;
|
|
void *dst;
|
|
u16 targetSpecies;
|
|
|
|
if (IsContest())
|
|
{
|
|
identity = 0;
|
|
targetSpecies = gContestResources->field_18->field_2;
|
|
personalityValue = gContestResources->field_18->field_8;
|
|
otId = gContestResources->field_18->field_C;
|
|
|
|
HandleLoadSpecialPokePic_DontHandleDeoxys(&gMonBackPicTable[targetSpecies],
|
|
gMonSpritesGfxPtr->sprites[0],
|
|
targetSpecies,
|
|
gContestResources->field_18->field_10);
|
|
}
|
|
else
|
|
{
|
|
identity = GetBankPosition(bankAtk);
|
|
|
|
if (GetBankSide(bankDef) == SIDE_OPPONENT)
|
|
targetSpecies = GetMonData(&gEnemyParty[gBattlePartyID[bankDef]], MON_DATA_SPECIES);
|
|
else
|
|
targetSpecies = GetMonData(&gPlayerParty[gBattlePartyID[bankDef]], MON_DATA_SPECIES);
|
|
|
|
if (GetBankSide(bankAtk) == SIDE_PLAYER)
|
|
{
|
|
personalityValue = GetMonData(&gPlayerParty[gBattlePartyID[bankAtk]], MON_DATA_PERSONALITY);
|
|
otId = GetMonData(&gPlayerParty[gBattlePartyID[bankAtk]], MON_DATA_OT_ID);
|
|
|
|
HandleLoadSpecialPokePic_DontHandleDeoxys(&gMonBackPicTable[targetSpecies],
|
|
gMonSpritesGfxPtr->sprites[identity],
|
|
targetSpecies,
|
|
gTransformedPersonalities[bankAtk]);
|
|
}
|
|
else
|
|
{
|
|
personalityValue = GetMonData(&gEnemyParty[gBattlePartyID[bankAtk]], MON_DATA_PERSONALITY);
|
|
otId = GetMonData(&gEnemyParty[gBattlePartyID[bankAtk]], MON_DATA_OT_ID);
|
|
|
|
HandleLoadSpecialPokePic_DontHandleDeoxys(&gMonFrontPicTable[targetSpecies],
|
|
gMonSpritesGfxPtr->sprites[identity],
|
|
targetSpecies,
|
|
gTransformedPersonalities[bankAtk]);
|
|
}
|
|
}
|
|
|
|
src = gMonSpritesGfxPtr->sprites[identity];
|
|
dst = (void *)(VRAM + 0x10000 + gSprites[gBankSpriteIds[bankAtk]].oam.tileNum * 32);
|
|
DmaCopy32(3, src, dst, 0x800);
|
|
paletteOffset = 0x100 + bankAtk * 16;
|
|
lzPaletteData = GetFrontSpritePalFromSpeciesAndPersonality(targetSpecies, otId, personalityValue);
|
|
LZDecompressWram(lzPaletteData, gDecompressionBuffer);
|
|
LoadPalette(gDecompressionBuffer, paletteOffset, 32);
|
|
|
|
if (targetSpecies == SPECIES_CASTFORM)
|
|
{
|
|
gSprites[gBankSpriteIds[bankAtk]].anims = gMonAnimationsSpriteAnimsPtrTable[targetSpecies];
|
|
LZDecompressWram(lzPaletteData, gBattleStruct->castformPalette[0]);
|
|
LoadPalette(gBattleStruct->castformPalette[0] + gBattleMonForms[bankDef] * 16, paletteOffset, 32);
|
|
}
|
|
|
|
BlendPalette(paletteOffset, 16, 6, 0x7FFF);
|
|
CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, 32);
|
|
|
|
if (!IsContest())
|
|
{
|
|
gBattleSpritesDataPtr->bankData[bankAtk].transformSpecies = targetSpecies;
|
|
gBattleMonForms[bankAtk] = gBattleMonForms[bankDef];
|
|
}
|
|
|
|
gSprites[gBankSpriteIds[bankAtk]].pos1.y = GetBankSpriteDefault_Y(bankAtk);
|
|
StartSpriteAnim(&gSprites[gBankSpriteIds[bankAtk]], gBattleMonForms[bankAtk]);
|
|
}
|
|
}
|
|
|
|
void BattleLoadSubstituteOrMonSpriteGfx(u8 bank, bool8 loadMonSprite)
|
|
{
|
|
u8 identity;
|
|
s32 i;
|
|
u32 var;
|
|
const void *substitutePal;
|
|
|
|
if (!loadMonSprite)
|
|
{
|
|
if (IsContest())
|
|
identity = 0;
|
|
else
|
|
identity = GetBankPosition(bank);
|
|
|
|
if (IsContest())
|
|
LZDecompressVram(gSubstituteDollTilemap, gMonSpritesGfxPtr->sprites[identity]);
|
|
else if (GetBankSide(bank) != SIDE_PLAYER)
|
|
LZDecompressVram(gSubstituteDollGfx, gMonSpritesGfxPtr->sprites[identity]);
|
|
else
|
|
LZDecompressVram(gSubstituteDollTilemap, gMonSpritesGfxPtr->sprites[identity]);
|
|
|
|
i = 1;
|
|
var = bank * 16;
|
|
substitutePal = gSubstituteDollPal;
|
|
for (; i < 4; i++)
|
|
{
|
|
register void *dmaSrc asm("r0") = gMonSpritesGfxPtr->sprites[identity];
|
|
void *dmaDst = (i * 0x800) + dmaSrc;
|
|
u32 dmaSize = 0x800;
|
|
DmaCopy32(3, dmaSrc, dmaDst, dmaSize);
|
|
i++;i--;
|
|
}
|
|
|
|
LoadCompressedPalette(substitutePal, 0x100 + var, 32);
|
|
}
|
|
else
|
|
{
|
|
if (!IsContest())
|
|
{
|
|
if (GetBankSide(bank) != SIDE_PLAYER)
|
|
BattleLoadOpponentMonSpriteGfx(&gEnemyParty[gBattlePartyID[bank]], bank);
|
|
else
|
|
BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[bank]], bank);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LoadBattleMonGfxAndAnimate(u8 bank, bool8 loadMonSprite, u8 spriteId)
|
|
{
|
|
BattleLoadSubstituteOrMonSpriteGfx(bank, loadMonSprite);
|
|
StartSpriteAnim(&gSprites[spriteId], gBattleMonForms[bank]);
|
|
|
|
if (!loadMonSprite)
|
|
gSprites[spriteId].pos1.y = GetSubstituteSpriteDefault_Y(bank);
|
|
else
|
|
gSprites[spriteId].pos1.y = GetBankSpriteDefault_Y(bank);
|
|
}
|
|
|
|
void TrySetBehindSubstituteSpriteBit(u8 bank, u16 move)
|
|
{
|
|
if (move == MOVE_SUBSTITUTE)
|
|
gBattleSpritesDataPtr->bankData[bank].behindSubstitute = 1;
|
|
}
|
|
|
|
void ClearBehindSubstituteBit(u8 bank)
|
|
{
|
|
gBattleSpritesDataPtr->bankData[bank].behindSubstitute = 0;
|
|
}
|
|
|
|
void HandleLowHpMusicChange(struct Pokemon *mon, u8 bank)
|
|
{
|
|
u16 hp = GetMonData(mon, MON_DATA_HP);
|
|
u16 maxHP = GetMonData(mon, MON_DATA_MAX_HP);
|
|
|
|
if (GetHPBarLevel(hp, maxHP) == HP_BAR_RED)
|
|
{
|
|
if (!gBattleSpritesDataPtr->bankData[bank].lowHpSong)
|
|
{
|
|
if (!gBattleSpritesDataPtr->bankData[bank ^ BIT_MON].lowHpSong)
|
|
PlaySE(SE_HINSI);
|
|
gBattleSpritesDataPtr->bankData[bank].lowHpSong = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gBattleSpritesDataPtr->bankData[bank].lowHpSong = 0;
|
|
if (!IsDoubleBattle())
|
|
{
|
|
m4aSongNumStop(SE_HINSI);
|
|
return;
|
|
}
|
|
if (IsDoubleBattle() && !gBattleSpritesDataPtr->bankData[bank ^ BIT_MON].lowHpSong)
|
|
{
|
|
m4aSongNumStop(SE_HINSI);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BattleStopLowHpSound(void)
|
|
{
|
|
u8 playerBank = GetBankByPosition(B_POSITION_PLAYER_LEFT);
|
|
|
|
gBattleSpritesDataPtr->bankData[playerBank].lowHpSong = 0;
|
|
if (IsDoubleBattle())
|
|
gBattleSpritesDataPtr->bankData[playerBank ^ BIT_MON].lowHpSong = 0;
|
|
|
|
m4aSongNumStop(SE_HINSI);
|
|
}
|
|
|
|
u8 GetMonHPBarLevel(struct Pokemon *mon)
|
|
{
|
|
u16 hp = GetMonData(mon, MON_DATA_HP);
|
|
u16 maxHP = GetMonData(mon, MON_DATA_MAX_HP);
|
|
|
|
return GetHPBarLevel(hp, maxHP);
|
|
}
|
|
|
|
void sub_805EAE8(void)
|
|
{
|
|
if (gMain.inBattle)
|
|
{
|
|
u8 playerBank1 = GetBankByPosition(B_POSITION_PLAYER_LEFT);
|
|
u8 playerBank2 = GetBankByPosition(B_POSITION_PLAYER_RIGHT);
|
|
u8 bank1PartyId = pokemon_order_func(gBattlePartyID[playerBank1]);
|
|
u8 bank2PartyId = pokemon_order_func(gBattlePartyID[playerBank2]);
|
|
|
|
if (GetMonData(&gPlayerParty[bank1PartyId], MON_DATA_HP) != 0)
|
|
HandleLowHpMusicChange(&gPlayerParty[bank1PartyId], playerBank1);
|
|
if (IsDoubleBattle() && GetMonData(&gPlayerParty[bank2PartyId], MON_DATA_HP) != 0)
|
|
HandleLowHpMusicChange(&gPlayerParty[bank2PartyId], playerBank2);
|
|
}
|
|
}
|
|
|
|
void sub_805EB9C(u8 affineMode)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < gBattleBanksCount; i++)
|
|
{
|
|
if (IsBankSpritePresent(i))
|
|
{
|
|
gSprites[gBankSpriteIds[i]].oam.affineMode = affineMode;
|
|
if (affineMode == 0)
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[i].field_6 = gSprites[gBankSpriteIds[i]].oam.matrixNum;
|
|
gSprites[gBankSpriteIds[i]].oam.matrixNum = 0;
|
|
}
|
|
else
|
|
{
|
|
gSprites[gBankSpriteIds[i]].oam.matrixNum = gBattleSpritesDataPtr->healthBoxesData[i].field_6;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#define tBank data[0]
|
|
|
|
void LoadAndCreateEnemyShadowSprites(void)
|
|
{
|
|
u8 bank;
|
|
|
|
LoadCompressedObjectPic(&gSpriteSheet_EnemyShadow);
|
|
|
|
bank = GetBankByPosition(B_POSITION_OPPONENT_LEFT);
|
|
gBattleSpritesDataPtr->healthBoxesData[bank].shadowSpriteId = CreateSprite(&gSpriteTemplate_EnemyShadow, GetBankCoord(bank, 0), GetBankCoord(bank, 1) + 29, 0xC8);
|
|
gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].shadowSpriteId].data[0] = bank;
|
|
|
|
if (IsDoubleBattle())
|
|
{
|
|
bank = GetBankByPosition(B_POSITION_OPPONENT_RIGHT);
|
|
gBattleSpritesDataPtr->healthBoxesData[bank].shadowSpriteId = CreateSprite(&gSpriteTemplate_EnemyShadow, GetBankCoord(bank, 0), GetBankCoord(bank, 1) + 29, 0xC8);
|
|
gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].shadowSpriteId].data[0] = bank;
|
|
}
|
|
}
|
|
|
|
void SpriteCB_EnemyShadow(struct Sprite *shadowSprite)
|
|
{
|
|
bool8 invisible = FALSE;
|
|
u8 bank = shadowSprite->tBank;
|
|
struct Sprite *bankSprite = &gSprites[gBankSpriteIds[bank]];
|
|
|
|
if (!bankSprite->inUse || !IsBankSpritePresent(bank))
|
|
{
|
|
shadowSprite->callback = SpriteCB_SetInvisible;
|
|
return;
|
|
}
|
|
if (gAnimScriptActive || bankSprite->invisible)
|
|
invisible = TRUE;
|
|
else if (gBattleSpritesDataPtr->bankData[bank].transformSpecies != SPECIES_NONE
|
|
&& gEnemyMonElevation[gBattleSpritesDataPtr->bankData[bank].transformSpecies] == 0)
|
|
invisible = TRUE;
|
|
|
|
if (gBattleSpritesDataPtr->bankData[bank].behindSubstitute)
|
|
invisible = TRUE;
|
|
|
|
shadowSprite->pos1.x = bankSprite->pos1.x;
|
|
shadowSprite->pos2.x = bankSprite->pos2.x;
|
|
shadowSprite->invisible = invisible;
|
|
}
|
|
|
|
#undef tBank
|
|
|
|
void SpriteCB_SetInvisible(struct Sprite *sprite)
|
|
{
|
|
sprite->invisible = 1;
|
|
}
|
|
|
|
void SetBankEnemyShadowSpriteCallback(u8 bank, u16 species)
|
|
{
|
|
if (GetBankSide(bank) == SIDE_PLAYER)
|
|
return;
|
|
|
|
if (gBattleSpritesDataPtr->bankData[bank].transformSpecies != SPECIES_NONE)
|
|
species = gBattleSpritesDataPtr->bankData[bank].transformSpecies;
|
|
|
|
if (gEnemyMonElevation[species] != 0)
|
|
gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].shadowSpriteId].callback = SpriteCB_EnemyShadow;
|
|
else
|
|
gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].shadowSpriteId].callback = SpriteCB_SetInvisible;
|
|
}
|
|
|
|
void EnemyShadowCallbackToSetInvisible(u8 bank)
|
|
{
|
|
gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].shadowSpriteId].callback = SpriteCB_SetInvisible;
|
|
}
|
|
|
|
void sub_805EF14(void)
|
|
{
|
|
u16 *vramPtr = (u16*)(VRAM + 0x240);
|
|
s32 i;
|
|
s32 j;
|
|
|
|
for (i = 0; i < 9; i++)
|
|
{
|
|
for (j = 0; j < 16; j++)
|
|
{
|
|
if (!(*vramPtr & 0xF000))
|
|
*vramPtr |= 0xF000;
|
|
if (!(*vramPtr & 0x0F00))
|
|
*vramPtr |= 0x0F00;
|
|
if (!(*vramPtr & 0x00F0))
|
|
*vramPtr |= 0x00F0;
|
|
if (!(*vramPtr & 0x000F))
|
|
*vramPtr |= 0x000F;
|
|
vramPtr++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ClearTemporarySpeciesSpriteData(u8 bank, bool8 dontClearSubstitute)
|
|
{
|
|
gBattleSpritesDataPtr->bankData[bank].transformSpecies = SPECIES_NONE;
|
|
gBattleMonForms[bank] = 0;
|
|
if (!dontClearSubstitute)
|
|
ClearBehindSubstituteBit(bank);
|
|
}
|
|
|
|
void AllocateMonSpritesGfx(void)
|
|
{
|
|
u8 i = 0, j;
|
|
|
|
gMonSpritesGfxPtr = NULL;
|
|
gMonSpritesGfxPtr = AllocZeroed(sizeof(*gMonSpritesGfxPtr));
|
|
gMonSpritesGfxPtr->firstDecompressed = AllocZeroed(0x8000);
|
|
|
|
for (i = 0; i < BATTLE_BANKS_COUNT; i++)
|
|
{
|
|
gMonSpritesGfxPtr->sprites[i] = gMonSpritesGfxPtr->firstDecompressed + (i * 0x2000);
|
|
*(gMonSpritesGfxPtr->templates + i) = gUnknown_08329D98[i];
|
|
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
gMonSpritesGfxPtr->field_74[i][j].data = gMonSpritesGfxPtr->sprites[i] + (j * 0x800);
|
|
gMonSpritesGfxPtr->field_74[i][j].size = 0x800;
|
|
}
|
|
|
|
gMonSpritesGfxPtr->templates[i].images = gMonSpritesGfxPtr->field_74[i];
|
|
}
|
|
|
|
gMonSpritesGfxPtr->barFontGfx = AllocZeroed(0x1000);
|
|
}
|
|
|
|
void FreeMonSpritesGfx(void)
|
|
{
|
|
if (gMonSpritesGfxPtr == NULL)
|
|
return;
|
|
|
|
if (gMonSpritesGfxPtr->field_17C != NULL)
|
|
FREE_AND_SET_NULL(gMonSpritesGfxPtr->field_17C);
|
|
if (gMonSpritesGfxPtr->field_178 != NULL)
|
|
FREE_AND_SET_NULL(gMonSpritesGfxPtr->field_178);
|
|
|
|
FREE_AND_SET_NULL(gMonSpritesGfxPtr->barFontGfx);
|
|
FREE_AND_SET_NULL(gMonSpritesGfxPtr->firstDecompressed);
|
|
gMonSpritesGfxPtr->sprites[0] = NULL;
|
|
gMonSpritesGfxPtr->sprites[1] = NULL;
|
|
gMonSpritesGfxPtr->sprites[2] = NULL;
|
|
gMonSpritesGfxPtr->sprites[3] = NULL;
|
|
FREE_AND_SET_NULL(gMonSpritesGfxPtr);
|
|
}
|
|
|
|
bool32 ShouldPlayNormalPokeCry(struct Pokemon *mon)
|
|
{
|
|
s16 hp, maxHP;
|
|
s32 barLevel;
|
|
|
|
if (GetMonData(mon, MON_DATA_STATUS) & (STATUS1_ANY | STATUS1_TOXIC_COUNTER))
|
|
return FALSE;
|
|
|
|
hp = GetMonData(mon, MON_DATA_HP);
|
|
maxHP = GetMonData(mon, MON_DATA_MAX_HP);
|
|
|
|
barLevel = GetHPBarLevel(hp, maxHP);
|
|
if (barLevel <= HP_BAR_YELLOW)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|