pokeemerald/src/battle_interface.c
2018-12-22 23:57:42 +01:00

3224 lines
100 KiB
C

#include "global.h"
#include "alloc.h"
#include "battle.h"
#include "pokemon.h"
#include "battle_controllers.h"
#include "battle_interface.h"
#include "graphics.h"
#include "sprite.h"
#include "window.h"
#include "string_util.h"
#include "text.h"
#include "sound.h"
#include "constants/songs.h"
#include "decompress.h"
#include "task.h"
#include "util.h"
#include "gpu_regs.h"
#include "battle_message.h"
#include "constants/species.h"
#include "pokedex.h"
#include "palette.h"
#include "international_string_util.h"
#include "safari_zone.h"
#include "battle_anim.h"
#include "constants/battle_anim.h"
#include "constants/rgb.h"
#include "data2.h"
#include "battle_debug.h"
#include "constants/battle_config.h"
struct TestingBar
{
s32 maxValue;
s32 oldValue;
s32 receivedValue;
u32 unkC_0:5;
u32 unk10;
};
enum
{
HEALTHBOX_GFX_0,
HEALTHBOX_GFX_1,
HEALTHBOX_GFX_2,
HEALTHBOX_GFX_HP_BAR_GREEN,
HEALTHBOX_GFX_4,
HEALTHBOX_GFX_5,
HEALTHBOX_GFX_6,
HEALTHBOX_GFX_7,
HEALTHBOX_GFX_8,
HEALTHBOX_GFX_9,
HEALTHBOX_GFX_10,
HEALTHBOX_GFX_11,
HEALTHBOX_GFX_12,
HEALTHBOX_GFX_13,
HEALTHBOX_GFX_14,
HEALTHBOX_GFX_15,
HEALTHBOX_GFX_16,
HEALTHBOX_GFX_17,
HEALTHBOX_GFX_18,
HEALTHBOX_GFX_19,
HEALTHBOX_GFX_20,
HEALTHBOX_GFX_STATUS_PSN_BATTLER0,
HEALTHBOX_GFX_22,
HEALTHBOX_GFX_23,
HEALTHBOX_GFX_STATUS_PRZ_BATTLER0,
HEALTHBOX_GFX_25,
HEALTHBOX_GFX_26,
HEALTHBOX_GFX_STATUS_SLP_BATTLER0,
HEALTHBOX_GFX_28,
HEALTHBOX_GFX_29,
HEALTHBOX_GFX_STATUS_FRZ_BATTLER0,
HEALTHBOX_GFX_31,
HEALTHBOX_GFX_32,
HEALTHBOX_GFX_STATUS_BRN_BATTLER0,
HEALTHBOX_GFX_34,
HEALTHBOX_GFX_35,
HEALTHBOX_GFX_36,
HEALTHBOX_GFX_37,
HEALTHBOX_GFX_38,
HEALTHBOX_GFX_39,
HEALTHBOX_GFX_40,
HEALTHBOX_GFX_41,
HEALTHBOX_GFX_42,
HEALTHBOX_GFX_43,
HEALTHBOX_GFX_44,
HEALTHBOX_GFX_45,
HEALTHBOX_GFX_46,
HEALTHBOX_GFX_HP_BAR_YELLOW,
HEALTHBOX_GFX_48,
HEALTHBOX_GFX_49,
HEALTHBOX_GFX_50,
HEALTHBOX_GFX_51,
HEALTHBOX_GFX_52,
HEALTHBOX_GFX_53,
HEALTHBOX_GFX_54,
HEALTHBOX_GFX_55,
HEALTHBOX_GFX_HP_BAR_RED,
HEALTHBOX_GFX_57,
HEALTHBOX_GFX_58,
HEALTHBOX_GFX_59,
HEALTHBOX_GFX_60,
HEALTHBOX_GFX_61,
HEALTHBOX_GFX_62,
HEALTHBOX_GFX_63,
HEALTHBOX_GFX_64,
HEALTHBOX_GFX_65,
HEALTHBOX_GFX_66,
HEALTHBOX_GFX_67,
HEALTHBOX_GFX_68,
HEALTHBOX_GFX_69,
HEALTHBOX_GFX_70,
HEALTHBOX_GFX_STATUS_PSN_BATTLER1,
HEALTHBOX_GFX_72,
HEALTHBOX_GFX_73,
HEALTHBOX_GFX_STATUS_PRZ_BATTLER1,
HEALTHBOX_GFX_75,
HEALTHBOX_GFX_76,
HEALTHBOX_GFX_STATUS_SLP_BATTLER1,
HEALTHBOX_GFX_78,
HEALTHBOX_GFX_79,
HEALTHBOX_GFX_STATUS_FRZ_BATTLER1,
HEALTHBOX_GFX_81,
HEALTHBOX_GFX_82,
HEALTHBOX_GFX_STATUS_BRN_BATTLER1,
HEALTHBOX_GFX_84,
HEALTHBOX_GFX_85,
HEALTHBOX_GFX_STATUS_PSN_BATTLER2,
HEALTHBOX_GFX_87,
HEALTHBOX_GFX_88,
HEALTHBOX_GFX_STATUS_PRZ_BATTLER2,
HEALTHBOX_GFX_90,
HEALTHBOX_GFX_91,
HEALTHBOX_GFX_STATUS_SLP_BATTLER2,
HEALTHBOX_GFX_93,
HEALTHBOX_GFX_94,
HEALTHBOX_GFX_STATUS_FRZ_BATTLER2,
HEALTHBOX_GFX_96,
HEALTHBOX_GFX_97,
HEALTHBOX_GFX_STATUS_BRN_BATTLER2,
HEALTHBOX_GFX_99,
HEALTHBOX_GFX_100,
HEALTHBOX_GFX_STATUS_PSN_BATTLER3,
HEALTHBOX_GFX_102,
HEALTHBOX_GFX_103,
HEALTHBOX_GFX_STATUS_PRZ_BATTLER3,
HEALTHBOX_GFX_105,
HEALTHBOX_GFX_106,
HEALTHBOX_GFX_STATUS_SLP_BATTLER3,
HEALTHBOX_GFX_108,
HEALTHBOX_GFX_109,
HEALTHBOX_GFX_STATUS_FRZ_BATTLER3,
HEALTHBOX_GFX_111,
HEALTHBOX_GFX_112,
HEALTHBOX_GFX_STATUS_BRN_BATTLER3,
HEALTHBOX_GFX_114,
HEALTHBOX_GFX_115,
HEALTHBOX_GFX_116,
HEALTHBOX_GFX_117,
};
extern const u8 *const gNatureNamePointers[];
// strings
extern const u8 gText_Slash[];
extern const u8 gText_HighlightDarkGrey[];
extern const u8 gText_DynColor2[];
extern const u8 gText_DynColor2Male[];
extern const u8 gText_DynColor1Female[];
// this file's functions
static const u8 *GetHealthboxElementGfxPtr(u8 elementId);
static u8* AddTextPrinterAndCreateWindowOnHealthbox(const u8 *str, u32 x, u32 y, u32 bgColor, u32 *windowId);
static void RemoveWindowOnHealthbox(u32 windowId);
static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent);
static void UpdateStatusIconInHealthbox(u8 healthboxSpriteId);
static void TextIntoHealthboxObject(void *dest, u8 *windowTileData, s32 windowWidth);
static void SafariTextIntoHealthboxObject(void *dest, u8 *windowTileData, u32 windowWidth);
static void HpTextIntoHealthboxObject(void *dest, u8 *windowTileData, u32 windowWidth);
static void FillHealthboxObject(void *dest, u32 arg1, u32 arg2);
static void sub_8073E08(u8 taskId);
static void sub_8073F98(u8 taskId);
static void sub_8073E64(u8 taskId);
static void SpriteCB_HealthBoxOther(struct Sprite *sprite);
static void SpriteCB_HealthBar(struct Sprite *sprite);
static void sub_8074158(struct Sprite *sprite);
static void sub_8074090(struct Sprite *sprite);
static void SpriteCB_StatusSummaryBar(struct Sprite *sprite);
static void SpriteCB_StatusSummaryBallsOnBattleStart(struct Sprite *sprite);
static void SpriteCB_StatusSummaryBallsOnSwitchout(struct Sprite *sprite);
static void SpriteCb_MegaTrigger(struct Sprite *sprite);
static u8 GetStatusIconForBattlerId(u8 statusElementId, u8 battlerId);
static s32 CalcNewBarValue(s32 maxValue, s32 currValue, s32 receivedValue, s32 *arg3, u8 arg4, u16 arg5);
static u8 GetScaledExpFraction(s32 currValue, s32 receivedValue, s32 maxValue, u8 scale);
static void MoveBattleBarGraphically(u8 battlerId, u8 whichBar);
static u8 CalcBarFilledPixels(s32 maxValue, s32 oldValue, s32 receivedValue, s32 *currValue, u8 *arg4, u8 scale);
static void sub_8074F88(struct TestingBar *barInfo, s32 *arg1, u16 *arg2);
static void SpriteCb_AbilityPopUp(struct Sprite *sprite);
static void Task_FreeAbilityPopUpGfx(u8 taskId);
// const rom data
static const struct OamData sUnknown_0832C138 =
{
.y = 0,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 0,
.shape = 1,
.x = 0,
.matrixNum = 0,
.size = 3,
.tileNum = 0,
.priority = 1,
.paletteNum = 0,
.affineParam = 0,
};
static const struct SpriteTemplate sHealthboxPlayerSpriteTemplates[2] =
{
{
.tileTag = TAG_HEALTHBOX_PLAYER1_TILE,
.paletteTag = TAG_HEALTHBOX_PAL,
.oam = &sUnknown_0832C138,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCallbackDummy
},
{
.tileTag = TAG_HEALTHBOX_PLAYER2_TILE,
.paletteTag = TAG_HEALTHBOX_PAL,
.oam = &sUnknown_0832C138,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCallbackDummy
}
};
static const struct SpriteTemplate sHealthboxOpponentSpriteTemplates[2] =
{
{
.tileTag = TAG_HEALTHBOX_OPPONENT1_TILE,
.paletteTag = TAG_HEALTHBOX_PAL,
.oam = &sUnknown_0832C138,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCallbackDummy
},
{
.tileTag = TAG_HEALTHBOX_OPPONENT2_TILE,
.paletteTag = TAG_HEALTHBOX_PAL,
.oam = &sUnknown_0832C138,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCallbackDummy
}
};
static const struct SpriteTemplate sHealthboxSafariSpriteTemplate =
{
.tileTag = TAG_HEALTHBOX_SAFARI_TILE,
.paletteTag = TAG_HEALTHBOX_PAL,
.oam = &sUnknown_0832C138,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCallbackDummy
};
static const struct OamData sOamData_Healthbar =
{
.y = 0,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 0,
.shape = 1,
.x = 0,
.matrixNum = 0,
.size = 1,
.tileNum = 0,
.priority = 1,
.paletteNum = 0,
.affineParam = 0,
};
static const struct SpriteTemplate sHealthbarSpriteTemplates[MAX_BATTLERS_COUNT] =
{
{
.tileTag = TAG_HEALTHBAR_PLAYER1_TILE,
.paletteTag = TAG_HEALTHBAR_PAL,
.oam = &sOamData_Healthbar,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_HealthBar
},
{
.tileTag = TAG_HEALTHBAR_OPPONENT1_TILE,
.paletteTag = TAG_HEALTHBAR_PAL,
.oam = &sOamData_Healthbar,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_HealthBar
},
{
.tileTag = TAG_HEALTHBAR_PLAYER2_TILE,
.paletteTag = TAG_HEALTHBAR_PAL,
.oam = &sOamData_Healthbar,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_HealthBar
},
{
.tileTag = TAG_HEALTHBAR_OPPONENT2_TILE,
.paletteTag = TAG_HEALTHBAR_PAL,
.oam = &sOamData_Healthbar,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_HealthBar
}
};
static const struct Subsprite sUnknown_0832C220[] =
{
{240, 0, 1, 3, 0, 1},
{48, 0, 0, 2, 32, 1},
{240, 32, 1, 1, 48, 1},
{16, 32, 1, 1, 52, 1},
{48, 32, 1, 1, 56, 1}
};
static const struct Subsprite sUnknown_0832C234[] =
{
{240, 0, 1, 3, 64, 1},
{48, 0, 0, 2, 96, 1},
{240, 32, 1, 1, 112, 1},
{16, 32, 1, 1, 116, 1},
{48, 32, 1, 1, 120, 1}
};
static const struct Subsprite sUnknown_0832C248[] =
{
{240, 0, 1, 3, 0, 1},
{48, 0, 0, 2, 32, 1}
};
static const struct Subsprite sUnknown_0832C250[] =
{
{240, 0, 1, 3, 0, 1},
{48, 0, 0, 2, 32, 1}
};
static const struct Subsprite sUnknown_0832C258[] =
{
{240, 0, 1, 1, 0, 1},
{16, 0, 1, 1, 4, 1}
};
static const struct Subsprite sUnknown_0832C260[] =
{
{240, 0, 1, 1, 0, 1},
{16, 0, 1, 1, 4, 1},
{224, 0, 0, 0, 8, 1}
};
// unused subsprite table
static const struct SubspriteTable sUnknown_0832C26C[] =
{
{ARRAY_COUNT(sUnknown_0832C220), sUnknown_0832C220},
{ARRAY_COUNT(sUnknown_0832C248), sUnknown_0832C248},
{ARRAY_COUNT(sUnknown_0832C234), sUnknown_0832C234},
{ARRAY_COUNT(sUnknown_0832C250), sUnknown_0832C250}
};
static const struct SubspriteTable sUnknown_0832C28C[] =
{
{ARRAY_COUNT(sUnknown_0832C258), sUnknown_0832C258},
{ARRAY_COUNT(sUnknown_0832C260), sUnknown_0832C260}
};
static const struct Subsprite sStatusSummaryBar_Subsprites_0[] =
{
{160, 0, 1, 1, 0, 1},
{192, 0, 1, 1, 4, 1},
{224, 0, 1, 1, 8, 1},
{0, 0, 1, 1, 12, 1}
};
static const struct Subsprite sUnknown_0832C2AC[] =
{
{160, 0, 1, 1, 0, 1},
{192, 0, 1, 1, 4, 1},
{224, 0, 1, 1, 8, 1},
{0, 0, 1, 1, 8, 1},
{32, 0, 1, 1, 8, 1},
{64, 0, 1, 1, 12, 1}
};
static const struct SubspriteTable sStatusSummaryBar_SubspriteTable[] =
{
{ARRAY_COUNT(sStatusSummaryBar_Subsprites_0), sStatusSummaryBar_Subsprites_0}
};
static const struct SubspriteTable sUnknown_0832C2CC[] =
{
{ARRAY_COUNT(sUnknown_0832C2AC), sUnknown_0832C2AC}
};
// unused unknown image
static const u8 sUnknown_0832C2D4[] = INCBIN_U8("graphics/battle_interface/unknown_32C2D4.4bpp");
static const struct CompressedSpriteSheet sStatusSummaryBarSpriteSheet =
{
gBattleInterface_BallStatusBarGfx, 0x200, TAG_STATUS_SUMMARY_BAR_TILE
};
static const struct SpritePalette sStatusSummaryBarSpritePal =
{
gBattleInterface_BallStatusBarPal, TAG_STATUS_SUMMARY_BAR_PAL
};
static const struct SpritePalette sStatusSummaryBallsSpritePal =
{
gBattleInterface_BallDisplayPal, TAG_STATUS_SUMMARY_BALLS_PAL
};
static const struct SpriteSheet sStatusSummaryBallsSpriteSheet =
{
gBattleInterface_BallDisplayGfx, 0x80, TAG_STATUS_SUMMARY_BALLS_TILE
};
// unused oam data
static const struct OamData sUnknown_0832C354 =
{
.y = 0,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 0,
.shape = 1,
.x = 0,
.matrixNum = 0,
.size = 3,
.tileNum = 0,
.priority = 1,
.paletteNum = 0,
.affineParam = 0,
};
static const struct OamData sOamData_StatusSummaryBalls =
{
.y = 0,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 0,
.shape = 0,
.x = 0,
.matrixNum = 0,
.size = 0,
.tileNum = 0,
.priority = 1,
.paletteNum = 0,
.affineParam = 0,
};
static const struct SpriteTemplate sStatusSummaryBarSpriteTemplates[2] =
{
{
.tileTag = TAG_STATUS_SUMMARY_BAR_TILE,
.paletteTag = TAG_STATUS_SUMMARY_BAR_PAL,
.oam = &sUnknown_0832C138,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_StatusSummaryBar
},
{
.tileTag = TAG_STATUS_SUMMARY_BAR_TILE,
.paletteTag = TAG_STATUS_SUMMARY_BAR_PAL,
.oam = &sUnknown_0832C138,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_StatusSummaryBar
}
};
static const struct SpriteTemplate sStatusSummaryBallsSpriteTemplates[2] =
{
{
.tileTag = TAG_STATUS_SUMMARY_BALLS_TILE,
.paletteTag = TAG_STATUS_SUMMARY_BALLS_PAL,
.oam = &sOamData_StatusSummaryBalls,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_StatusSummaryBallsOnBattleStart
},
{
.tileTag = TAG_STATUS_SUMMARY_BALLS_TILE,
.paletteTag = TAG_STATUS_SUMMARY_BALLS_PAL,
.oam = &sOamData_StatusSummaryBalls,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_StatusSummaryBallsOnBattleStart
}
};
// possibly text
static const u8 sUnknown_0832C3C4[] =
{
0xfc, 0x01, 0x01, 0xfc, 0x02, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
// possibly text
static const u8 sUnknown_0832C3D8[] =
{
0xfc, 0x01, 0x01, 0xfc, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
enum
{
PAL_STATUS_PSN,
PAL_STATUS_PAR,
PAL_STATUS_SLP,
PAL_STATUS_FRZ,
PAL_STATUS_BRN
};
static const u16 sStatusIconColors[] =
{
[PAL_STATUS_PSN] = RGB(24, 12, 24),
[PAL_STATUS_PAR] = RGB(23, 23, 3),
[PAL_STATUS_SLP] = RGB(20, 20, 17),
[PAL_STATUS_FRZ] = RGB(17, 22, 28),
[PAL_STATUS_BRN] = RGB(28, 14, 10),
};
static const struct WindowTemplate sHealthboxWindowTemplate = {0, 0, 0, 8, 2, 0, 0}; // width = 8, height = 2
static const u8 sMegaTriggerGfx[] = INCBIN_U8("graphics/battle_interface/mega_trigger.4bpp");
static const u16 sMegaTriggerPal[] = INCBIN_U16("graphics/battle_interface/mega_trigger.gbapal");
static const struct SpriteSheet sSpriteSheet_MegaTrigger =
{
sMegaTriggerGfx, sizeof(sMegaTriggerGfx), TAG_MEGA_TRIGGER_TILE
};
static const struct SpritePalette sSpritePalette_MegaTrigger =
{
sMegaTriggerPal, TAG_MEGA_TRIGGER_PAL
};
static const struct OamData sOamData_MegaTrigger =
{
.y = 0,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 0,
.shape = ST_OAM_SQUARE,
.x = 0,
.matrixNum = 0,
.size = 2,
.tileNum = 0,
.priority = 1,
.paletteNum = 0,
.affineParam = 0,
};
static const union AnimCmd sSpriteAnim_MegaTriggerOff[] =
{
ANIMCMD_FRAME(0, 0),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_MegaTriggerOn[] =
{
ANIMCMD_FRAME(16, 0),
ANIMCMD_END
};
static const union AnimCmd *const sSpriteAnimTable_MegaTrigger[] =
{
sSpriteAnim_MegaTriggerOff,
sSpriteAnim_MegaTriggerOn,
};
static const struct SpriteTemplate sSpriteTemplate_MegaTrigger =
{
.tileTag = TAG_MEGA_TRIGGER_TILE,
.paletteTag = TAG_MEGA_TRIGGER_PAL,
.oam = &sOamData_MegaTrigger,
.anims = sSpriteAnimTable_MegaTrigger,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCb_MegaTrigger
};
// code
static s32 DummiedOutFunction(s16 unused1, s16 unused2, s32 unused3)
{
return 9;
}
#ifdef NONMATCHING
static void sub_8072308(s16 arg0, u16 *arg1, u8 arg2)
{
s8 i, j;
u8 array[4];
u8 *arrayPtr;
s32 r9, vaaa;
for (i = 0; i < 4; i++)
array[i] = 0;
i = 3;
r9 = -1;
arrayPtr = array;
while (1)
{
if (arg0 > 0)
{
array[i] = arg0 % 10;
arg0 = arg0 / 10;
i--;
}
else
{
break;
}
}
for (; i > -1; i--)
{
array[i] = 0xFF;
}
if (arrayPtr[3] == 0xFF)
arrayPtr[3] = 0;
if (arg2 == 0)
{
for (i = 0, j = 0; i < 4; i++)
{
if (array[j] == 0xFF)
{
arg1[j] &= 0xFC00;
arg1[j] |= 0x1E;
arg1[i + 0x20] &= 0xFC00;
arg1[i + 0x20] |= 0x1E;
}
else
{
arg1[j] &= 0xFC00;
arg1[j] |= array[j] + 0x14;
arg1[i + 0x20] &= 0xFC00;
arg1[i + 0x20] |= array[i] + 0x34;
}
j++;
}
}
else
{
for (i = 0; i < 4; i++)
{
if (array[i] == 0xFF)
{
arg1[i] &= 0xFC00;
arg1[i] |= 0x1E;
arg1[i + 0x20] &= 0xFC00;
arg1[i + 0x20] |= 0x1E;
}
else
{
arg1[i] &= 0xFC00;
arg1[i] |= array[i] + 0x14;
arg1[i + 0x20] &= 0xFC00;
arg1[i + 0x20] |= array[i] + 0x34;
}
}
}
}
#else
NAKED
static void sub_8072308(s16 arg0, u16 *arg1, u8 arg2)
{
asm(".syntax unified\n\
push {r4-r7,lr}\n\
mov r7, r10\n\
mov r6, r9\n\
mov r5, r8\n\
push {r5-r7}\n\
sub sp, 0x4\n\
adds r7, r1, 0\n\
lsls r0, 16\n\
lsrs r5, r0, 16\n\
lsls r2, 24\n\
lsrs r2, 24\n\
mov r10, r2\n\
movs r3, 0\n\
movs r2, 0\n\
_08072324:\n\
lsls r0, r3, 24\n\
asrs r0, 24\n\
mov r3, sp\n\
adds r1, r3, r0\n\
strb r2, [r1]\n\
adds r0, 0x1\n\
lsls r0, 24\n\
lsrs r3, r0, 24\n\
asrs r0, 24\n\
cmp r0, 0x3\n\
ble _08072324\n\
movs r3, 0x3\n\
movs r0, 0x1\n\
negs r0, r0\n\
mov r9, r0\n\
mov r8, sp\n\
_08072344:\n\
lsls r0, r5, 16\n\
asrs r6, r0, 16\n\
cmp r6, 0\n\
ble _08072372\n\
lsls r4, r3, 24\n\
asrs r4, 24\n\
mov r1, sp\n\
adds r5, r1, r4\n\
adds r0, r6, 0\n\
movs r1, 0xA\n\
bl __modsi3\n\
strb r0, [r5]\n\
adds r0, r6, 0\n\
movs r1, 0xA\n\
bl __divsi3\n\
lsls r0, 16\n\
lsrs r5, r0, 16\n\
subs r4, 0x1\n\
lsls r4, 24\n\
lsrs r3, r4, 24\n\
b _08072344\n\
_08072372:\n\
lsls r1, r3, 24\n\
asrs r0, r1, 24\n\
cmp r0, r9\n\
ble _08072396\n\
movs r4, 0xFF\n\
movs r3, 0x1\n\
negs r3, r3\n\
_08072380:\n\
asrs r2, r1, 24\n\
mov r5, sp\n\
adds r1, r5, r2\n\
ldrb r0, [r1]\n\
orrs r0, r4\n\
strb r0, [r1]\n\
subs r2, 0x1\n\
lsls r1, r2, 24\n\
asrs r0, r1, 24\n\
cmp r0, r3\n\
bgt _08072380\n\
_08072396:\n\
mov r1, r8\n\
ldrb r0, [r1, 0x3]\n\
cmp r0, 0xFF\n\
bne _080723A2\n\
movs r0, 0\n\
strb r0, [r1, 0x3]\n\
_080723A2:\n\
mov r2, r10\n\
cmp r2, 0\n\
bne _08072432\n\
movs r3, 0\n\
movs r1, 0\n\
movs r6, 0xFC\n\
lsls r6, 8\n\
movs r5, 0x1E\n\
mov r12, r5\n\
_080723B4:\n\
lsls r1, 24\n\
asrs r2, r1, 24\n\
mov r0, sp\n\
adds r5, r0, r2\n\
ldrb r0, [r5]\n\
mov r8, r1\n\
cmp r0, 0xFF\n\
bne _080723EA\n\
lsls r1, r2, 1\n\
adds r1, r7\n\
ldrh r2, [r1]\n\
adds r0, r6, 0\n\
ands r0, r2\n\
mov r2, r12\n\
orrs r0, r2\n\
strh r0, [r1]\n\
lsls r3, 24\n\
asrs r1, r3, 23\n\
adds r1, r7\n\
adds r1, 0x40\n\
ldrh r2, [r1]\n\
adds r0, r6, 0\n\
ands r0, r2\n\
mov r5, r12\n\
orrs r0, r5\n\
strh r0, [r1]\n\
b _0807241A\n\
_080723EA:\n\
lsls r2, 1\n\
adds r2, r7\n\
ldrh r0, [r2]\n\
adds r1, r6, 0\n\
ands r1, r0\n\
ldrb r0, [r5]\n\
adds r0, 0x14\n\
orrs r1, r0\n\
strh r1, [r2]\n\
lsls r4, r3, 24\n\
asrs r3, r4, 24\n\
lsls r2, r3, 1\n\
adds r2, r7\n\
adds r2, 0x40\n\
ldrh r0, [r2]\n\
adds r1, r6, 0\n\
ands r1, r0\n\
mov r5, sp\n\
adds r0, r5, r3\n\
ldrb r0, [r0]\n\
adds r0, 0x34\n\
orrs r1, r0\n\
strh r1, [r2]\n\
adds r3, r4, 0\n\
_0807241A:\n\
movs r0, 0x80\n\
lsls r0, 17\n\
add r0, r8\n\
lsrs r1, r0, 24\n\
movs r2, 0x80\n\
lsls r2, 17\n\
adds r0, r3, r2\n\
lsrs r3, r0, 24\n\
asrs r0, 24\n\
cmp r0, 0x3\n\
ble _080723B4\n\
b _08072496\n\
_08072432:\n\
movs r3, 0\n\
movs r4, 0xFC\n\
lsls r4, 8\n\
movs r6, 0x1E\n\
_0807243A:\n\
lsls r1, r3, 24\n\
asrs r2, r1, 24\n\
mov r3, sp\n\
adds r5, r3, r2\n\
ldrb r0, [r5]\n\
adds r3, r1, 0\n\
cmp r0, 0xFF\n\
bne _08072466\n\
lsls r1, r2, 1\n\
adds r1, r7\n\
ldrh r2, [r1]\n\
adds r0, r4, 0\n\
ands r0, r2\n\
orrs r0, r6\n\
strh r0, [r1]\n\
adds r1, 0x40\n\
ldrh r2, [r1]\n\
adds r0, r4, 0\n\
ands r0, r2\n\
orrs r0, r6\n\
strh r0, [r1]\n\
b _08072488\n\
_08072466:\n\
lsls r2, 1\n\
adds r2, r7\n\
ldrh r0, [r2]\n\
adds r1, r4, 0\n\
ands r1, r0\n\
ldrb r0, [r5]\n\
adds r0, 0x14\n\
orrs r1, r0\n\
strh r1, [r2]\n\
adds r2, 0x40\n\
ldrh r0, [r2]\n\
adds r1, r4, 0\n\
ands r1, r0\n\
ldrb r0, [r5]\n\
adds r0, 0x34\n\
orrs r1, r0\n\
strh r1, [r2]\n\
_08072488:\n\
movs r5, 0x80\n\
lsls r5, 17\n\
adds r0, r3, r5\n\
lsrs r3, r0, 24\n\
asrs r0, 24\n\
cmp r0, 0x3\n\
ble _0807243A\n\
_08072496:\n\
add sp, 0x4\n\
pop {r3-r5}\n\
mov r8, r3\n\
mov r9, r4\n\
mov r10, r5\n\
pop {r4-r7}\n\
pop {r0}\n\
bx r0\n\
.syntax divided");
}
#endif // NONMATCHING
void sub_80724A8(s16 arg0, s16 arg1, u16 *arg2)
{
arg2[4] = 0x1E;
sub_8072308(arg1, arg2, 0);
sub_8072308(arg0, arg2 + 5, 1);
}
// Because the healthbox is too large to fit into one sprite, it is divided into two sprites.
// healthboxLeft or healthboxMain is the left part that is used as the 'main' sprite.
// healthboxRight or healthboxOther is the right part of the healthbox.
// There's also the third sprite under name of healthbarSprite that refers to the healthbar visible on the healtbox.
// data fields for healthboxMain
// oam.affineParam holds healthboxRight spriteId
#define hMain_HealthBarSpriteId data[5]
#define hMain_Battler data[6]
#define hMain_Data7 data[7]
// data fields for healthboxRight
#define hOther_HealthBoxSpriteId data[5]
// data fields for healthbar
#define hBar_HealthBoxSpriteId data[5]
#define hBar_Data6 data[6]
u8 CreateBattlerHealthboxSprites(u8 battlerId)
{
s16 data6 = 0;
u8 healthboxLeftSpriteId, healthboxRightSpriteId;
u8 healthbarSpriteId;
struct Sprite *healthBarSpritePtr;
if (!IsDoubleBattle())
{
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
{
healthboxLeftSpriteId = CreateSprite(&sHealthboxPlayerSpriteTemplates[0], 240, 160, 1);
healthboxRightSpriteId = CreateSpriteAtEnd(&sHealthboxPlayerSpriteTemplates[0], 240, 160, 1);
gSprites[healthboxLeftSpriteId].oam.shape = 0;
gSprites[healthboxRightSpriteId].oam.shape = 0;
gSprites[healthboxRightSpriteId].oam.tileNum += 64;
}
else
{
healthboxLeftSpriteId = CreateSprite(&sHealthboxOpponentSpriteTemplates[0], 240, 160, 1);
healthboxRightSpriteId = CreateSpriteAtEnd(&sHealthboxOpponentSpriteTemplates[0], 240, 160, 1);
gSprites[healthboxRightSpriteId].oam.tileNum += 32;
data6 = 2;
}
gSprites[healthboxLeftSpriteId].oam.affineParam = healthboxRightSpriteId;
gSprites[healthboxRightSpriteId].hOther_HealthBoxSpriteId = healthboxLeftSpriteId;
gSprites[healthboxRightSpriteId].callback = SpriteCB_HealthBoxOther;
}
else
{
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
{
healthboxLeftSpriteId = CreateSprite(&sHealthboxPlayerSpriteTemplates[GetBattlerPosition(battlerId) / 2], 240, 160, 1);
healthboxRightSpriteId = CreateSpriteAtEnd(&sHealthboxPlayerSpriteTemplates[GetBattlerPosition(battlerId) / 2], 240, 160, 1);
gSprites[healthboxLeftSpriteId].oam.affineParam = healthboxRightSpriteId;
gSprites[healthboxRightSpriteId].hOther_HealthBoxSpriteId = healthboxLeftSpriteId;
gSprites[healthboxRightSpriteId].oam.tileNum += 32;
gSprites[healthboxRightSpriteId].callback = SpriteCB_HealthBoxOther;
data6 = 1;
}
else
{
healthboxLeftSpriteId = CreateSprite(&sHealthboxOpponentSpriteTemplates[GetBattlerPosition(battlerId) / 2], 240, 160, 1);
healthboxRightSpriteId = CreateSpriteAtEnd(&sHealthboxOpponentSpriteTemplates[GetBattlerPosition(battlerId) / 2], 240, 160, 1);
gSprites[healthboxLeftSpriteId].oam.affineParam = healthboxRightSpriteId;
gSprites[healthboxRightSpriteId].hOther_HealthBoxSpriteId = healthboxLeftSpriteId;
gSprites[healthboxRightSpriteId].oam.tileNum += 32;
gSprites[healthboxRightSpriteId].callback = SpriteCB_HealthBoxOther;
data6 = 2;
}
}
healthbarSpriteId = CreateSpriteAtEnd(&sHealthbarSpriteTemplates[gBattlerPositions[battlerId]], 140, 60, 0);
healthBarSpritePtr = &gSprites[healthbarSpriteId];
SetSubspriteTables(healthBarSpritePtr, &sUnknown_0832C28C[GetBattlerSide(battlerId)]);
healthBarSpritePtr->subspriteMode = 2;
healthBarSpritePtr->oam.priority = 1;
CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_1), (void*)(OBJ_VRAM0 + healthBarSpritePtr->oam.tileNum * TILE_SIZE_4BPP), 64);
gSprites[healthboxLeftSpriteId].hMain_HealthBarSpriteId = healthbarSpriteId;
gSprites[healthboxLeftSpriteId].hMain_Battler = battlerId;
gSprites[healthboxLeftSpriteId].invisible = TRUE;
gSprites[healthboxRightSpriteId].invisible = TRUE;
healthBarSpritePtr->hBar_HealthBoxSpriteId = healthboxLeftSpriteId;
healthBarSpritePtr->hBar_Data6 = data6;
healthBarSpritePtr->invisible = TRUE;
return healthboxLeftSpriteId;
}
u8 CreateSafariPlayerHealthboxSprites(void)
{
u8 healthboxLeftSpriteId, healthboxRightSpriteId;
healthboxLeftSpriteId = CreateSprite(&sHealthboxSafariSpriteTemplate, 240, 160, 1);
healthboxRightSpriteId = CreateSpriteAtEnd(&sHealthboxSafariSpriteTemplate, 240, 160, 1);
gSprites[healthboxLeftSpriteId].oam.shape = 0;
gSprites[healthboxRightSpriteId].oam.shape = 0;
gSprites[healthboxRightSpriteId].oam.tileNum += 64;
gSprites[healthboxLeftSpriteId].oam.affineParam = healthboxRightSpriteId;
gSprites[healthboxRightSpriteId].hOther_HealthBoxSpriteId = healthboxLeftSpriteId;
gSprites[healthboxRightSpriteId].callback = SpriteCB_HealthBoxOther;
return healthboxLeftSpriteId;
}
static const u8 *GetHealthboxElementGfxPtr(u8 elementId)
{
return gHealthboxElementsGfxTable[elementId];
}
// Syncs the position of healthbar accordingly with the healthbox.
static void SpriteCB_HealthBar(struct Sprite *sprite)
{
u8 healthboxSpriteId = sprite->hBar_HealthBoxSpriteId;
switch (sprite->hBar_Data6)
{
case 0:
sprite->pos1.x = gSprites[healthboxSpriteId].pos1.x + 16;
sprite->pos1.y = gSprites[healthboxSpriteId].pos1.y;
break;
case 1:
sprite->pos1.x = gSprites[healthboxSpriteId].pos1.x + 16;
sprite->pos1.y = gSprites[healthboxSpriteId].pos1.y;
break;
case 2:
default:
sprite->pos1.x = gSprites[healthboxSpriteId].pos1.x + 8;
sprite->pos1.y = gSprites[healthboxSpriteId].pos1.y;
break;
}
sprite->pos2.x = gSprites[healthboxSpriteId].pos2.x;
sprite->pos2.y = gSprites[healthboxSpriteId].pos2.y;
}
static void SpriteCB_HealthBoxOther(struct Sprite *sprite)
{
u8 healthboxMainSpriteId = sprite->hOther_HealthBoxSpriteId;
sprite->pos1.x = gSprites[healthboxMainSpriteId].pos1.x + 64;
sprite->pos1.y = gSprites[healthboxMainSpriteId].pos1.y;
sprite->pos2.x = gSprites[healthboxMainSpriteId].pos2.x;
sprite->pos2.y = gSprites[healthboxMainSpriteId].pos2.y;
}
void SetBattleBarStruct(u8 battlerId, u8 healthboxSpriteId, s32 maxVal, s32 oldVal, s32 receivedValue)
{
gBattleSpritesDataPtr->battleBars[battlerId].healthboxSpriteId = healthboxSpriteId;
gBattleSpritesDataPtr->battleBars[battlerId].maxValue = maxVal;
gBattleSpritesDataPtr->battleBars[battlerId].oldValue = oldVal;
gBattleSpritesDataPtr->battleBars[battlerId].receivedValue = receivedValue;
gBattleSpritesDataPtr->battleBars[battlerId].currValue = -32768;
}
void SetHealthboxSpriteInvisible(u8 healthboxSpriteId)
{
gSprites[healthboxSpriteId].invisible = TRUE;
gSprites[gSprites[healthboxSpriteId].hMain_HealthBarSpriteId].invisible = TRUE;
gSprites[gSprites[healthboxSpriteId].oam.affineParam].invisible = TRUE;
}
void SetHealthboxSpriteVisible(u8 healthboxSpriteId)
{
gSprites[healthboxSpriteId].invisible = FALSE;
gSprites[gSprites[healthboxSpriteId].hMain_HealthBarSpriteId].invisible = FALSE;
gSprites[gSprites[healthboxSpriteId].oam.affineParam].invisible = FALSE;
}
static void UpdateSpritePos(u8 spriteId, s16 x, s16 y)
{
gSprites[spriteId].pos1.x = x;
gSprites[spriteId].pos1.y = y;
}
void DestoryHealthboxSprite(u8 healthboxSpriteId)
{
DestroySprite(&gSprites[gSprites[healthboxSpriteId].oam.affineParam]);
DestroySprite(&gSprites[gSprites[healthboxSpriteId].hMain_HealthBarSpriteId]);
DestroySprite(&gSprites[healthboxSpriteId]);
}
void DummyBattleInterfaceFunc(u8 healthboxSpriteId, bool8 isDoubleBattleBattlerOnly)
{
}
void UpdateOamPriorityInAllHealthboxes(u8 priority)
{
s32 i;
for (i = 0; i < gBattlersCount; i++)
{
u8 healthboxLeftSpriteId = gHealthboxSpriteIds[i];
u8 healthboxRightSpriteId = gSprites[gHealthboxSpriteIds[i]].oam.affineParam;
u8 healthbarSpriteId = gSprites[gHealthboxSpriteIds[i]].hMain_HealthBarSpriteId;
gSprites[healthboxLeftSpriteId].oam.priority = priority;
gSprites[healthboxRightSpriteId].oam.priority = priority;
gSprites[healthbarSpriteId].oam.priority = priority;
}
}
void InitBattlerHealthboxCoords(u8 battler)
{
s16 x = 0, y = 0;
if (!IsDoubleBattle())
{
if (GetBattlerSide(battler) != B_SIDE_PLAYER)
x = 44, y = 30;
else
x = 158, y = 88;
}
else
{
switch (GetBattlerPosition(battler))
{
case B_POSITION_PLAYER_LEFT:
x = 159, y = 76;
break;
case B_POSITION_PLAYER_RIGHT:
x = 171, y = 101;
break;
case B_POSITION_OPPONENT_LEFT:
x = 44, y = 19;
break;
case B_POSITION_OPPONENT_RIGHT:
x = 32, y = 44;
break;
}
}
UpdateSpritePos(gHealthboxSpriteIds[battler], x, y);
}
static void UpdateLvlInHealthbox(u8 healthboxSpriteId, u8 lvl)
{
u32 windowId, spriteTileNum;
u8 *windowTileData;
u8 text[16];
u32 xPos, var1;
void *objVram;
text[0] = 0xF9;
text[1] = 5;
xPos = (u32) ConvertIntToDecimalStringN(text + 2, lvl, STR_CONV_MODE_LEFT_ALIGN, 3);
// Alright, that part was unmatchable. It's basically doing:
// xPos = 5 * (3 - (u32)(&text[2]));
xPos--;
xPos--;
xPos -= ((u32)(text));
var1 = (3 - xPos);
xPos = 4 * var1;
xPos += var1;
windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, xPos, 3, 2, &windowId);
spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum * TILE_SIZE_4BPP;
if (GetBattlerSide(gSprites[healthboxSpriteId].hMain_Battler) == B_SIDE_PLAYER)
{
objVram = (void*)(OBJ_VRAM0);
if (!IsDoubleBattle())
objVram += spriteTileNum + 0x820;
else
objVram += spriteTileNum + 0x420;
}
else
{
objVram = (void*)(OBJ_VRAM0);
objVram += spriteTileNum + 0x400;
}
TextIntoHealthboxObject(objVram, windowTileData, 3);
RemoveWindowOnHealthbox(windowId);
}
void UpdateHpTextInHealthbox(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent)
{
u32 windowId, spriteTileNum;
u8 *windowTileData;
u8 text[32];
void *objVram;
if (GetBattlerSide(gSprites[healthboxSpriteId].hMain_Battler) == B_SIDE_PLAYER && !IsDoubleBattle())
{
spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum * TILE_SIZE_4BPP;
if (maxOrCurrent != HP_CURRENT) // singles, max
{
ConvertIntToDecimalStringN(text, value, STR_CONV_MODE_RIGHT_ALIGN, 3);
windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, 0, 5, 2, &windowId);
objVram = (void*)(OBJ_VRAM0);
objVram += spriteTileNum + 0xB40;
HpTextIntoHealthboxObject(objVram, windowTileData, 2);
RemoveWindowOnHealthbox(windowId);
}
else // singles, current
{
ConvertIntToDecimalStringN(text, value, STR_CONV_MODE_RIGHT_ALIGN, 3);
text[3] = CHAR_SLASH;
text[4] = EOS;
windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, 4, 5, 2, &windowId);
objVram = (void*)(OBJ_VRAM0);
objVram += spriteTileNum + 0x3E0;
HpTextIntoHealthboxObject(objVram, windowTileData, 1);
objVram = (void*)(OBJ_VRAM0);
objVram += spriteTileNum + 0xB00;
HpTextIntoHealthboxObject(objVram, windowTileData + 0x20, 2);
RemoveWindowOnHealthbox(windowId);
}
}
else
{
u8 battler;
memcpy(text, sUnknown_0832C3C4, sizeof(sUnknown_0832C3C4));
battler = gSprites[healthboxSpriteId].hMain_Battler;
if (IsDoubleBattle() == TRUE)
{
UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, value, maxOrCurrent);
}
else if (gBattleSpritesDataPtr->battlerData[battler].hpNumbersNoBars) // don't print text if only bars are visible
{
u32 var;
u8 i;
if (GetBattlerSide(gSprites[healthboxSpriteId].data[6]) == B_SIDE_PLAYER)
{
if (maxOrCurrent == HP_CURRENT)
var = 29;
else
var = 89;
}
else
{
if (maxOrCurrent == HP_CURRENT)
var = 21;
else
var = 49;
}
ConvertIntToDecimalStringN(text + 6, value, STR_CONV_MODE_LEADING_ZEROS, 3);
RenderTextFont9(gMonSpritesGfxPtr->barFontGfx, 9, text);
for (i = 0; i < 3; i++)
{
CpuCopy32(&gMonSpritesGfxPtr->barFontGfx[i * 64 + 32],
(void*)((OBJ_VRAM0) + TILE_SIZE_4BPP * (gSprites[healthboxSpriteId].oam.tileNum + var + i)),
0x20);
}
}
}
}
static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent)
{
u32 windowId, spriteTileNum;
u8 *windowTileData;
u8 text[32];
void *objVram;
if (GetBattlerSide(gSprites[healthboxSpriteId].hMain_Battler) == B_SIDE_PLAYER)
{
if (gBattleSpritesDataPtr->battlerData[gSprites[healthboxSpriteId].data[6]].hpNumbersNoBars) // don't print text if only bars are visible
{
spriteTileNum = gSprites[gSprites[healthboxSpriteId].data[5]].oam.tileNum * TILE_SIZE_4BPP;
objVram = (void*)(OBJ_VRAM0) + spriteTileNum;
if (maxOrCurrent != HP_CURRENT) // doubles, max hp
{
ConvertIntToDecimalStringN(text, value, STR_CONV_MODE_RIGHT_ALIGN, 3);
windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, 0, 5, 0, &windowId);
HpTextIntoHealthboxObject((void*)(OBJ_VRAM0) + spriteTileNum + 0xC0, windowTileData, 2);
RemoveWindowOnHealthbox(windowId);
CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_116),
(void*)(OBJ_VRAM0 + 0x680) + (gSprites[healthboxSpriteId].oam.tileNum * TILE_SIZE_4BPP),
0x20);
}
else
{
ConvertIntToDecimalStringN(text, value, STR_CONV_MODE_RIGHT_ALIGN, 3);
text[3] = CHAR_SLASH;
text[4] = EOS;
windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, 4, 5, 0, &windowId);
FillHealthboxObject(objVram, 0, 3); // Erases HP bar leftover.
HpTextIntoHealthboxObject((void*)(OBJ_VRAM0 + 0x60) + spriteTileNum, windowTileData, 3);
RemoveWindowOnHealthbox(windowId);
}
}
}
else
{
u8 battlerId;
memcpy(text, sUnknown_0832C3D8, sizeof(sUnknown_0832C3D8));
battlerId = gSprites[healthboxSpriteId].hMain_Battler;
if (gBattleSpritesDataPtr->battlerData[battlerId].hpNumbersNoBars) // don't print text if only bars are visible
{
u8 var = 4;
u8 r7;
u8 *txtPtr;
u8 i;
if (maxOrCurrent == HP_CURRENT)
var = 0;
r7 = gSprites[healthboxSpriteId].data[5];
txtPtr = ConvertIntToDecimalStringN(text + 6, value, STR_CONV_MODE_RIGHT_ALIGN, 3);
if (!maxOrCurrent)
StringCopy(txtPtr, gText_Slash);
RenderTextFont9(gMonSpritesGfxPtr->barFontGfx, 9, text);
for (i = var; i < var + 3; i++)
{
if (i < 3)
{
CpuCopy32(&gMonSpritesGfxPtr->barFontGfx[((i - var) * 64) + 32],
(void*)((OBJ_VRAM0) + 32 * (1 + gSprites[r7].oam.tileNum + i)),
0x20);
}
else
{
CpuCopy32(&gMonSpritesGfxPtr->barFontGfx[((i - var) * 64) + 32],
(void*)((OBJ_VRAM0 + 0x20) + 32 * (i + gSprites[r7].oam.tileNum)),
0x20);
}
}
if (maxOrCurrent == HP_CURRENT)
{
CpuCopy32(&gMonSpritesGfxPtr->barFontGfx[224],
(void*)((OBJ_VRAM0) + ((gSprites[r7].oam.tileNum + 4) * TILE_SIZE_4BPP)),
0x20);
CpuFill32(0, (void*)((OBJ_VRAM0) + (gSprites[r7].oam.tileNum * TILE_SIZE_4BPP)), 0x20);
}
else
{
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) // Impossible to reach part, because the battlerId is from the opponent's side.
{
CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_116),
(void*)(OBJ_VRAM0) + ((gSprites[healthboxSpriteId].oam.tileNum + 52) * TILE_SIZE_4BPP),
0x20);
}
}
}
}
}
// Prints mon's nature, catch and flee rate. Probably used to test pokeblock-related features.
static void PrintSafariMonInfo(u8 healthboxSpriteId, struct Pokemon *mon)
{
u8 text[20];
s32 j, spriteTileNum;
u8 *barFontGfx;
u8 i, var, nature, healthBarSpriteId;
memcpy(text, sUnknown_0832C3C4, sizeof(sUnknown_0832C3C4));
barFontGfx = &gMonSpritesGfxPtr->barFontGfx[0x520 + (GetBattlerPosition(gSprites[healthboxSpriteId].hMain_Battler) * 384)];
var = 5;
nature = GetNature(mon);
StringCopy(text + 6, gNatureNamePointers[nature]);
RenderTextFont9(barFontGfx, 9, text);
for (j = 6, i = 0; i < var; i++, j++)
{
u8 elementId;
if ((text[j] >= 55 && text[j] <= 74) || (text[j] >= 135 && text[j] <= 154))
elementId = 44;
else if ((text[j] >= 75 && text[j] <= 79) || (text[j] >= 155 && text[j] <= 159))
elementId = 45;
else
elementId = 43;
CpuCopy32(GetHealthboxElementGfxPtr(elementId), barFontGfx + (i * 64), 0x20);
}
for (j = 1; j < var + 1; j++)
{
spriteTileNum = (gSprites[healthboxSpriteId].oam.tileNum + (j - (j / 8 * 8)) + (j / 8 * 64)) * TILE_SIZE_4BPP;
CpuCopy32(barFontGfx, (void*)(OBJ_VRAM0) + (spriteTileNum), 0x20);
barFontGfx += 0x20;
spriteTileNum = (8 + gSprites[healthboxSpriteId].oam.tileNum + (j - (j / 8 * 8)) + (j / 8 * 64)) * TILE_SIZE_4BPP;
CpuCopy32(barFontGfx, (void*)(OBJ_VRAM0) + (spriteTileNum), 0x20);
barFontGfx += 0x20;
}
healthBarSpriteId = gSprites[healthboxSpriteId].hMain_HealthBarSpriteId;
ConvertIntToDecimalStringN(text + 6, gBattleStruct->safariCatchFactor, STR_CONV_MODE_RIGHT_ALIGN, 2);
ConvertIntToDecimalStringN(text + 9, gBattleStruct->safariEscapeFactor, STR_CONV_MODE_RIGHT_ALIGN, 2);
text[5] = CHAR_SPACE;
text[8] = CHAR_SLASH;
RenderTextFont9(gMonSpritesGfxPtr->barFontGfx, 9, text);
j = healthBarSpriteId; // Needed to match for some reason.
for (j = 0; j < 5; j++)
{
if (j <= 1)
{
CpuCopy32(&gMonSpritesGfxPtr->barFontGfx[0x40 * j + 0x20],
(void*)(OBJ_VRAM0) + (gSprites[healthBarSpriteId].oam.tileNum + 2 + j) * TILE_SIZE_4BPP,
32);
}
else
{
CpuCopy32(&gMonSpritesGfxPtr->barFontGfx[0x40 * j + 0x20],
(void*)(OBJ_VRAM0 + 0xC0) + (j + gSprites[healthBarSpriteId].oam.tileNum) * TILE_SIZE_4BPP,
32);
}
}
}
void SwapHpBarsWithHpText(void)
{
s32 i;
u8 healthBarSpriteId;
for (i = 0; i < gBattlersCount; i++)
{
if (gSprites[gHealthboxSpriteIds[i]].callback == SpriteCallbackDummy
&& GetBattlerSide(i) != B_SIDE_OPPONENT
&& (IsDoubleBattle() || GetBattlerSide(i) != B_SIDE_PLAYER))
{
bool8 noBars;
gBattleSpritesDataPtr->battlerData[i].hpNumbersNoBars ^= 1;
noBars = gBattleSpritesDataPtr->battlerData[i].hpNumbersNoBars;
if (GetBattlerSide(i) == B_SIDE_PLAYER)
{
if (!IsDoubleBattle())
continue;
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
continue;
if (noBars == TRUE) // bars to text
{
healthBarSpriteId = gSprites[gHealthboxSpriteIds[i]].hMain_HealthBarSpriteId;
CpuFill32(0, (void*)(OBJ_VRAM0 + gSprites[healthBarSpriteId].oam.tileNum * TILE_SIZE_4BPP), 0x100);
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_HP), HP_CURRENT);
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP), HP_MAX);
}
else // text to bars
{
UpdateStatusIconInHealthbox(gHealthboxSpriteIds[i]);
UpdateHealthboxAttribute(gHealthboxSpriteIds[i], &gPlayerParty[gBattlerPartyIndexes[i]], HEALTHBOX_HEALTH_BAR);
CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_117), (void*)(OBJ_VRAM0 + 0x680 + gSprites[gHealthboxSpriteIds[i]].oam.tileNum * TILE_SIZE_4BPP), 32);
}
}
else
{
if (noBars == TRUE) // bars to text
{
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
{
// Most likely a debug function.
PrintSafariMonInfo(gHealthboxSpriteIds[i], &gEnemyParty[gBattlerPartyIndexes[i]]);
}
else
{
healthBarSpriteId = gSprites[gHealthboxSpriteIds[i]].hMain_HealthBarSpriteId;
CpuFill32(0, (void *)(OBJ_VRAM0 + gSprites[healthBarSpriteId].oam.tileNum * 32), 0x100);
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_HP), HP_CURRENT);
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP), HP_MAX);
}
}
else // text to bars
{
UpdateStatusIconInHealthbox(gHealthboxSpriteIds[i]);
UpdateHealthboxAttribute(gHealthboxSpriteIds[i], &gEnemyParty[gBattlerPartyIndexes[i]], HEALTHBOX_HEALTH_BAR);
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
UpdateHealthboxAttribute(gHealthboxSpriteIds[i], &gEnemyParty[gBattlerPartyIndexes[i]], HEALTHBOX_NICK);
}
}
gSprites[gHealthboxSpriteIds[i]].hMain_Data7 ^= 1;
}
}
}
// Mega Evolution gfx functions.
void ChangeMegaTriggerSprite(u8 spriteId, u8 animId)
{
StartSpriteAnim(&gSprites[spriteId], animId);
}
#define SINGLES_MEGA_TRIGGER_POS_X_OPTIMAL (30)
#define SINGLES_MEGA_TRIGGER_POS_X_PRIORITY (31)
#define SINGLES_MEGA_TRIGGER_POS_X_SLIDE (15)
#define SINGLES_MEGA_TRIGGER_POS_Y_DIFF (-11)
#define DOUBLES_MEGA_TRIGGER_POS_X_OPTIMAL (30)
#define DOUBLES_MEGA_TRIGGER_POS_X_PRIORITY (31)
#define DOUBLES_MEGA_TRIGGER_POS_X_SLIDE (15)
#define DOUBLES_MEGA_TRIGGER_POS_Y_DIFF (-4)
#define tBattler data[0]
#define tHide data[1]
void CreateMegaTriggerSprite(u8 battlerId, u8 palId)
{
LoadSpritePalette(&sSpritePalette_MegaTrigger);
if (GetSpriteTileStartByTag(TAG_MEGA_TRIGGER_TILE) == 0xFFFF)
LoadSpriteSheet(&sSpriteSheet_MegaTrigger);
if (gBattleStruct->mega.triggerSpriteId == 0xFF)
{
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
gBattleStruct->mega.triggerSpriteId = CreateSprite(&sSpriteTemplate_MegaTrigger,
gSprites[gHealthboxSpriteIds[battlerId]].pos1.x - DOUBLES_MEGA_TRIGGER_POS_X_SLIDE,
gSprites[gHealthboxSpriteIds[battlerId]].pos1.y - DOUBLES_MEGA_TRIGGER_POS_Y_DIFF, 0);
else
gBattleStruct->mega.triggerSpriteId = CreateSprite(&sSpriteTemplate_MegaTrigger,
gSprites[gHealthboxSpriteIds[battlerId]].pos1.x - SINGLES_MEGA_TRIGGER_POS_X_SLIDE,
gSprites[gHealthboxSpriteIds[battlerId]].pos1.y - SINGLES_MEGA_TRIGGER_POS_Y_DIFF, 0);
}
gSprites[gBattleStruct->mega.triggerSpriteId].tBattler = battlerId;
gSprites[gBattleStruct->mega.triggerSpriteId].tHide = FALSE;
ChangeMegaTriggerSprite(gBattleStruct->mega.triggerSpriteId, palId);
}
static void SpriteCb_MegaTrigger(struct Sprite *sprite)
{
s32 xSlide, xPriority, xOptimal;
s32 yDiff;
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
xSlide = DOUBLES_MEGA_TRIGGER_POS_X_SLIDE;
xPriority = DOUBLES_MEGA_TRIGGER_POS_X_PRIORITY;
xOptimal = DOUBLES_MEGA_TRIGGER_POS_X_OPTIMAL;
yDiff = DOUBLES_MEGA_TRIGGER_POS_Y_DIFF;
}
else
{
xSlide = SINGLES_MEGA_TRIGGER_POS_X_SLIDE;
xPriority = SINGLES_MEGA_TRIGGER_POS_X_PRIORITY;
xOptimal = SINGLES_MEGA_TRIGGER_POS_X_OPTIMAL;
yDiff = SINGLES_MEGA_TRIGGER_POS_Y_DIFF;
}
if (sprite->tHide)
{
if (sprite->pos1.x != gSprites[gHealthboxSpriteIds[sprite->tBattler]].pos1.x - xSlide)
sprite->pos1.x++;
if (sprite->pos1.x >= gSprites[gHealthboxSpriteIds[sprite->tBattler]].pos1.x - xPriority)
sprite->oam.priority = 2;
else
sprite->oam.priority = 1;
sprite->pos1.y = gSprites[gHealthboxSpriteIds[sprite->tBattler]].pos1.y - yDiff;
sprite->pos2.y = gSprites[gHealthboxSpriteIds[sprite->tBattler]].pos2.y - yDiff;
if (sprite->pos1.x == gSprites[gHealthboxSpriteIds[sprite->tBattler]].pos1.x - xSlide)
DestroyMegaTriggerSprite();
}
else
{
if (sprite->pos1.x != gSprites[gHealthboxSpriteIds[sprite->tBattler]].pos1.x - xOptimal)
sprite->pos1.x--;
if (sprite->pos1.x >= gSprites[gHealthboxSpriteIds[sprite->tBattler]].pos1.x - xPriority)
sprite->oam.priority = 2;
else
sprite->oam.priority = 1;
sprite->pos1.y = gSprites[gHealthboxSpriteIds[sprite->tBattler]].pos1.y - yDiff;
sprite->pos2.y = gSprites[gHealthboxSpriteIds[sprite->tBattler]].pos2.y - yDiff;
}
}
bool32 IsMegaTriggerSpriteActive(void)
{
if (GetSpriteTileStartByTag(TAG_MEGA_TRIGGER_TILE) == 0xFFFF)
return FALSE;
else if (IndexOfSpritePaletteTag(TAG_MEGA_TRIGGER_PAL) != 0xFF)
return TRUE;
else
return FALSE;
}
void HideMegaTriggerSprite(void)
{
ChangeMegaTriggerSprite(gBattleStruct->mega.triggerSpriteId, 0);
gSprites[gBattleStruct->mega.triggerSpriteId].tHide = TRUE;
}
void DestroyMegaTriggerSprite(void)
{
FreeSpritePaletteByTag(TAG_MEGA_TRIGGER_PAL);
FreeSpriteTilesByTag(TAG_MEGA_TRIGGER_TILE);
if (gBattleStruct->mega.triggerSpriteId != 0xFF)
DestroySprite(&gSprites[gBattleStruct->mega.triggerSpriteId]);
gBattleStruct->mega.triggerSpriteId = 0xFF;
}
#undef tBattler
#undef tHide
#define tBattler data[0]
#define tSummaryBarSpriteId data[1]
#define tBallIconSpriteId(n) data[3 + n]
#define tIsBattleStart data[10]
#define tData15 data[15]
u8 CreatePartyStatusSummarySprites(u8 battlerId, struct HpAndStatus *partyInfo, u8 arg2, bool8 isBattleStart)
{
bool8 isOpponent;
s16 bar_X, bar_Y, bar_pos2_X, bar_data0;
s32 i, j, var;
u8 summaryBarSpriteId;
u8 ballIconSpritesIds[PARTY_SIZE];
u8 taskId;
if (!arg2 || GetBattlerPosition(battlerId) != B_POSITION_OPPONENT_RIGHT)
{
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
{
isOpponent = FALSE;
bar_X = 136, bar_Y = 96;
bar_pos2_X = 100;
bar_data0 = -5;
}
else
{
isOpponent = TRUE;
if (!arg2 || !IsDoubleBattle())
bar_X = 104, bar_Y = 40;
else
bar_X = 104, bar_Y = 16;
bar_pos2_X = -100;
bar_data0 = 5;
}
}
else
{
isOpponent = TRUE;
bar_X = 104, bar_Y = 40;
bar_pos2_X = -100;
bar_data0 = 5;
}
LoadCompressedSpriteSheetUsingHeap(&sStatusSummaryBarSpriteSheet);
LoadSpriteSheet(&sStatusSummaryBallsSpriteSheet);
LoadSpritePalette(&sStatusSummaryBarSpritePal);
LoadSpritePalette(&sStatusSummaryBallsSpritePal);
summaryBarSpriteId = CreateSprite(&sStatusSummaryBarSpriteTemplates[isOpponent], bar_X, bar_Y, 10);
SetSubspriteTables(&gSprites[summaryBarSpriteId], sStatusSummaryBar_SubspriteTable);
gSprites[summaryBarSpriteId].pos2.x = bar_pos2_X;
gSprites[summaryBarSpriteId].data[0] = bar_data0;
if (isOpponent)
{
gSprites[summaryBarSpriteId].pos1.x -= 96;
gSprites[summaryBarSpriteId].oam.matrixNum = 8;
}
else
{
gSprites[summaryBarSpriteId].pos1.x += 96;
}
for (i = 0; i < PARTY_SIZE; i++)
{
ballIconSpritesIds[i] = CreateSpriteAtEnd(&sStatusSummaryBallsSpriteTemplates[isOpponent], bar_X, bar_Y - 4, 9);
if (!isBattleStart)
gSprites[ballIconSpritesIds[i]].callback = SpriteCB_StatusSummaryBallsOnSwitchout;
if (!isOpponent)
{
gSprites[ballIconSpritesIds[i]].pos2.x = 0;
gSprites[ballIconSpritesIds[i]].pos2.y = 0;
}
gSprites[ballIconSpritesIds[i]].data[0] = summaryBarSpriteId;
if (!isOpponent)
{
gSprites[ballIconSpritesIds[i]].pos1.x += 10 * i + 24;
gSprites[ballIconSpritesIds[i]].data[1] = i * 7 + 10;
gSprites[ballIconSpritesIds[i]].pos2.x = 120;
}
else
{
gSprites[ballIconSpritesIds[i]].pos1.x -= 10 * (5 - i) + 24;
gSprites[ballIconSpritesIds[i]].data[1] = (6 - i) * 7 + 10;
gSprites[ballIconSpritesIds[i]].pos2.x = -120;
}
gSprites[ballIconSpritesIds[i]].data[2] = isOpponent;
}
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
{
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
for (i = 0; i < PARTY_SIZE; i++)
{
if (partyInfo[i].hp == 0xFFFF) // empty slot or an egg
{
gSprites[ballIconSpritesIds[i]].oam.tileNum += 1;
gSprites[ballIconSpritesIds[i]].data[7] = 1;
}
else if (partyInfo[i].hp == 0) // fainted mon
{
gSprites[ballIconSpritesIds[i]].oam.tileNum += 3;
}
else if (partyInfo[i].status != 0) // mon with major status
{
gSprites[ballIconSpritesIds[i]].oam.tileNum += 2;
}
}
}
else
{
for (i = 0, var = 5, j = 0; j < PARTY_SIZE; j++)
{
if (partyInfo[j].hp == 0xFFFF) // empty slot or an egg
{
gSprites[ballIconSpritesIds[var]].oam.tileNum += 1;
gSprites[ballIconSpritesIds[var]].data[7] = 1;
var--;
continue;
}
else if (partyInfo[j].hp == 0) // fainted mon
{
gSprites[ballIconSpritesIds[i]].oam.tileNum += 3;
}
else if (gBattleTypeFlags & BATTLE_TYPE_ARENA && gBattleStruct->arenaLostPlayerMons & gBitTable[j])
{
gSprites[ballIconSpritesIds[i]].oam.tileNum += 3;
}
else if (partyInfo[j].status != 0) // mon with major status
{
gSprites[ballIconSpritesIds[i]].oam.tileNum += 2;
}
i++;
}
}
}
else
{
if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS))
{
for (var = 5, i = 0; i < PARTY_SIZE; i++)
{
if (partyInfo[i].hp == 0xFFFF) // empty slot or an egg
{
gSprites[ballIconSpritesIds[var]].oam.tileNum += 1;
gSprites[ballIconSpritesIds[var]].data[7] = 1;
}
else if (partyInfo[i].hp == 0) // fainted mon
{
gSprites[ballIconSpritesIds[var]].oam.tileNum += 3;
}
else if (partyInfo[i].status != 0) // mon with major status
{
gSprites[ballIconSpritesIds[var]].oam.tileNum += 2;
}
var--;
}
}
else
{
for (var = 0, i = 0, j = 0; j < PARTY_SIZE; j++)
{
if (partyInfo[j].hp == 0xFFFF) // empty slot or an egg
{
gSprites[ballIconSpritesIds[i]].oam.tileNum += 1;
gSprites[ballIconSpritesIds[i]].data[7] = 1;
i++;
continue;
}
else if (partyInfo[j].hp == 0) // fainted mon
{
gSprites[ballIconSpritesIds[5 - var]].oam.tileNum += 3;
}
else if (gBattleTypeFlags & BATTLE_TYPE_ARENA && gBattleStruct->arenaLostOpponentMons & gBitTable[j]) // hmm...?
{
gSprites[ballIconSpritesIds[5 - var]].oam.tileNum += 3;
}
else if (partyInfo[j].status != 0) // mon with major status
{
gSprites[ballIconSpritesIds[5 - var]].oam.tileNum += 2;
}
var++;
}
}
}
taskId = CreateTask(TaskDummy, 5);
gTasks[taskId].tBattler = battlerId;
gTasks[taskId].tSummaryBarSpriteId = summaryBarSpriteId;
for (i = 0; i < PARTY_SIZE; i++)
gTasks[taskId].tBallIconSpriteId(i) = ballIconSpritesIds[i];
gTasks[taskId].tIsBattleStart = isBattleStart;
if (isBattleStart)
{
gBattleSpritesDataPtr->animationData->field_9_x1C++;
}
PlaySE12WithPanning(SE_TB_START, 0);
return taskId;
}
void Task_HidePartyStatusSummary(u8 taskId)
{
u8 ballIconSpriteIds[PARTY_SIZE];
bool8 isBattleStart;
u8 summaryBarSpriteId;
u8 battlerId;
s32 i;
isBattleStart = gTasks[taskId].tIsBattleStart;
summaryBarSpriteId = gTasks[taskId].tSummaryBarSpriteId;
battlerId = gTasks[taskId].tBattler;
for (i = 0; i < PARTY_SIZE; i++)
ballIconSpriteIds[i] = gTasks[taskId].tBallIconSpriteId(i);
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND);
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(16, 0));
gTasks[taskId].tData15 = 16;
for (i = 0; i < PARTY_SIZE; i++)
gSprites[ballIconSpriteIds[i]].oam.objMode = 1;
gSprites[summaryBarSpriteId].oam.objMode = 1;
if (isBattleStart)
{
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
{
gSprites[ballIconSpriteIds[5 - i]].data[1] = 7 * i;
gSprites[ballIconSpriteIds[5 - i]].data[3] = 0;
gSprites[ballIconSpriteIds[5 - i]].data[4] = 0;
gSprites[ballIconSpriteIds[5 - i]].callback = sub_8074158;
}
else
{
gSprites[ballIconSpriteIds[i]].data[1] = 7 * i;
gSprites[ballIconSpriteIds[i]].data[3] = 0;
gSprites[ballIconSpriteIds[i]].data[4] = 0;
gSprites[ballIconSpriteIds[i]].callback = sub_8074158;
}
}
gSprites[summaryBarSpriteId].data[0] /= 2;
gSprites[summaryBarSpriteId].data[1] = 0;
gSprites[summaryBarSpriteId].callback = sub_8074090;
SetSubspriteTables(&gSprites[summaryBarSpriteId], sUnknown_0832C2CC);
gTasks[taskId].func = sub_8073E08;
}
else
{
gTasks[taskId].func = sub_8073F98;
}
}
static void sub_8073E08(u8 taskId)
{
if ((gTasks[taskId].data[11]++ % 2) == 0)
{
if (--gTasks[taskId].tData15 < 0)
return;
SetGpuReg(REG_OFFSET_BLDALPHA, (gTasks[taskId].data[15]) | ((16 - gTasks[taskId].data[15]) << 8));
}
if (gTasks[taskId].tData15 == 0)
gTasks[taskId].func = sub_8073E64;
}
static void sub_8073E64(u8 taskId)
{
u8 ballIconSpriteIds[PARTY_SIZE];
s32 i;
u8 battlerId = gTasks[taskId].tBattler;
if (--gTasks[taskId].tData15 == -1)
{
u8 summaryBarSpriteId = gTasks[taskId].tSummaryBarSpriteId;
for (i = 0; i < PARTY_SIZE; i++)
ballIconSpriteIds[i] = gTasks[taskId].tBallIconSpriteId(i);
gBattleSpritesDataPtr->animationData->field_9_x1C--;
if (gBattleSpritesDataPtr->animationData->field_9_x1C == 0)
{
DestroySpriteAndFreeResources(&gSprites[summaryBarSpriteId]);
DestroySpriteAndFreeResources(&gSprites[ballIconSpriteIds[0]]);
}
else
{
FreeSpriteOamMatrix(&gSprites[summaryBarSpriteId]);
DestroySprite(&gSprites[summaryBarSpriteId]);
FreeSpriteOamMatrix(&gSprites[ballIconSpriteIds[0]]);
DestroySprite(&gSprites[ballIconSpriteIds[0]]);
}
for (i = 1; i < PARTY_SIZE; i++)
DestroySprite(&gSprites[ballIconSpriteIds[i]]);
}
else if (gTasks[taskId].tData15 == -3)
{
gBattleSpritesDataPtr->healthBoxesData[battlerId].partyStatusSummaryShown = 0;
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
DestroyTask(taskId);
}
}
static void sub_8073F98(u8 taskId)
{
u8 ballIconSpriteIds[PARTY_SIZE];
s32 i;
u8 battlerId = gTasks[taskId].tBattler;
if (--gTasks[taskId].tData15 >= 0)
{
SetGpuReg(REG_OFFSET_BLDALPHA, (gTasks[taskId].tData15) | ((16 - gTasks[taskId].tData15) << 8));
}
else if (gTasks[taskId].tData15 == -1)
{
u8 summaryBarSpriteId = gTasks[taskId].tSummaryBarSpriteId;
for (i = 0; i < PARTY_SIZE; i++)
ballIconSpriteIds[i] = gTasks[taskId].tBallIconSpriteId(i);
DestroySpriteAndFreeResources(&gSprites[summaryBarSpriteId]);
DestroySpriteAndFreeResources(&gSprites[ballIconSpriteIds[0]]);
for (i = 1; i < PARTY_SIZE; i++)
DestroySprite(&gSprites[ballIconSpriteIds[i]]);
}
else if (gTasks[taskId].tData15 == -3)
{
gBattleSpritesDataPtr->healthBoxesData[battlerId].partyStatusSummaryShown = 0;
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
DestroyTask(taskId);
}
}
#undef tBattler
#undef tSummaryBarSpriteId
#undef tBallIconSpriteId
#undef tIsBattleStart
#undef tData15
static void SpriteCB_StatusSummaryBar(struct Sprite *sprite)
{
if (sprite->pos2.x != 0)
sprite->pos2.x += sprite->data[0];
}
static void sub_8074090(struct Sprite *sprite)
{
sprite->data[1] += 32;
if (sprite->data[0] > 0)
sprite->pos2.x += sprite->data[1] >> 4;
else
sprite->pos2.x -= sprite->data[1] >> 4;
sprite->data[1] &= 0xF;
}
static void SpriteCB_StatusSummaryBallsOnBattleStart(struct Sprite *sprite)
{
u8 var1;
u16 var2;
s8 pan;
if (sprite->data[1] > 0)
{
sprite->data[1]--;
return;
}
var1 = sprite->data[2];
var2 = sprite->data[3];
var2 += 56;
sprite->data[3] = var2 & 0xFFF0;
if (var1 != 0)
{
sprite->pos2.x += var2 >> 4;
if (sprite->pos2.x > 0)
sprite->pos2.x = 0;
}
else
{
sprite->pos2.x -= var2 >> 4;
if (sprite->pos2.x < 0)
sprite->pos2.x = 0;
}
if (sprite->pos2.x == 0)
{
pan = SOUND_PAN_TARGET;
if (var1 != 0)
pan = SOUND_PAN_ATTACKER;
if (sprite->data[7] != 0)
PlaySE2WithPanning(SE_TB_KARA, pan);
else
PlaySE1WithPanning(SE_TB_KON, pan);
sprite->callback = SpriteCallbackDummy;
}
}
static void sub_8074158(struct Sprite *sprite)
{
u8 var1;
u16 var2;
if (sprite->data[1] > 0)
{
sprite->data[1]--;
return;
}
var1 = sprite->data[2];
var2 = sprite->data[3];
var2 += 56;
sprite->data[3] = var2 & 0xFFF0;
if (var1 != 0)
sprite->pos2.x += var2 >> 4;
else
sprite->pos2.x -= var2 >> 4;
if (sprite->pos2.x + sprite->pos1.x > 248
|| sprite->pos2.x + sprite->pos1.x < -8)
{
sprite->invisible = TRUE;
sprite->callback = SpriteCallbackDummy;
}
}
static void SpriteCB_StatusSummaryBallsOnSwitchout(struct Sprite *sprite)
{
u8 barSpriteId = sprite->data[0];
sprite->pos2.x = gSprites[barSpriteId].pos2.x;
sprite->pos2.y = gSprites[barSpriteId].pos2.y;
}
static void UpdateNickInHealthbox(u8 healthboxSpriteId, struct Pokemon *mon)
{
u8 nickname[POKEMON_NAME_LENGTH + 1];
void *ptr;
const u8 *genderTxt;
u32 windowId, spriteTileNum;
u8 *windowTileData;
u16 species;
u8 gender;
StringCopy(gDisplayedStringBattle, gText_HighlightDarkGrey);
GetMonData(mon, MON_DATA_NICKNAME, nickname);
StringGetEnd10(nickname);
ptr = StringAppend(gDisplayedStringBattle, nickname);
gender = GetMonGender(mon);
species = GetMonData(mon, MON_DATA_SPECIES);
if ((species == SPECIES_NIDORAN_F || species == SPECIES_NIDORAN_M) && StringCompare(nickname, gSpeciesNames[species]) == 0)
gender = 100;
// AddTextPrinterAndCreateWindowOnHealthbox's arguments are the same in all 3 cases.
// It's possible they may have been different in early development phases.
switch (gender)
{
default:
StringCopy(ptr, gText_DynColor2);
windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gDisplayedStringBattle, 0, 3, 2, &windowId);
break;
case MON_MALE:
StringCopy(ptr, gText_DynColor2Male);
windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gDisplayedStringBattle, 0, 3, 2, &windowId);
break;
case MON_FEMALE:
StringCopy(ptr, gText_DynColor1Female);
windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gDisplayedStringBattle, 0, 3, 2, &windowId);
break;
}
spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum * TILE_SIZE_4BPP;
if (GetBattlerSide(gSprites[healthboxSpriteId].data[6]) == B_SIDE_PLAYER)
{
TextIntoHealthboxObject((void*)(VRAM + 0x10040 + spriteTileNum), windowTileData, 6);
ptr = (void*)(OBJ_VRAM0);
if (!IsDoubleBattle())
ptr += spriteTileNum + 0x800;
else
ptr += spriteTileNum + 0x400;
TextIntoHealthboxObject(ptr, windowTileData + 0xC0, 1);
}
else
{
TextIntoHealthboxObject((void*)(VRAM + 0x10020 + spriteTileNum), windowTileData, 7);
}
RemoveWindowOnHealthbox(windowId);
}
static void TryAddPokeballIconToHealthbox(u8 healthboxSpriteId, bool8 noStatus)
{
u8 battlerId, healthBarSpriteId;
if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL)
return;
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
return;
battlerId = gSprites[healthboxSpriteId].hMain_Battler;
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
return;
if (!GetSetPokedexFlag(SpeciesToNationalPokedexNum(GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES)), FLAG_GET_CAUGHT))
return;
healthBarSpriteId = gSprites[healthboxSpriteId].hMain_HealthBarSpriteId;
if (noStatus)
CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_70), (void*)(OBJ_VRAM0 + (gSprites[healthBarSpriteId].oam.tileNum + 8) * TILE_SIZE_4BPP), 32);
else
CpuFill32(0, (void*)(OBJ_VRAM0 + (gSprites[healthBarSpriteId].oam.tileNum + 8) * TILE_SIZE_4BPP), 32);
}
static void UpdateStatusIconInHealthbox(u8 healthboxSpriteId)
{
s32 i;
u8 battlerId, healthBarSpriteId;
u32 status, pltAdder;
const u8 *statusGfxPtr;
s16 tileNumAdder;
u8 statusPalId;
battlerId = gSprites[healthboxSpriteId].hMain_Battler;
healthBarSpriteId = gSprites[healthboxSpriteId].hMain_HealthBarSpriteId;
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
{
status = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_STATUS);
if (!IsDoubleBattle())
tileNumAdder = 0x1A;
else
tileNumAdder = 0x12;
}
else
{
status = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_STATUS);
tileNumAdder = 0x11;
}
if (status & STATUS1_SLEEP)
{
statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBattlerId(HEALTHBOX_GFX_STATUS_SLP_BATTLER0, battlerId));
statusPalId = PAL_STATUS_SLP;
}
else if (status & STATUS1_PSN_ANY)
{
statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBattlerId(HEALTHBOX_GFX_STATUS_PSN_BATTLER0, battlerId));
statusPalId = PAL_STATUS_PSN;
}
else if (status & STATUS1_BURN)
{
statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBattlerId(HEALTHBOX_GFX_STATUS_BRN_BATTLER0, battlerId));
statusPalId = PAL_STATUS_BRN;
}
else if (status & STATUS1_FREEZE)
{
statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBattlerId(HEALTHBOX_GFX_STATUS_FRZ_BATTLER0, battlerId));
statusPalId = PAL_STATUS_FRZ;
}
else if (status & STATUS1_PARALYSIS)
{
statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBattlerId(HEALTHBOX_GFX_STATUS_PRZ_BATTLER0, battlerId));
statusPalId = PAL_STATUS_PAR;
}
else
{
statusGfxPtr = GetHealthboxElementGfxPtr(HEALTHBOX_GFX_39);
for (i = 0; i < 3; i++)
CpuCopy32(statusGfxPtr, (void*)(OBJ_VRAM0 + (gSprites[healthboxSpriteId].oam.tileNum + tileNumAdder + i) * TILE_SIZE_4BPP), 32);
if (!gBattleSpritesDataPtr->battlerData[battlerId].hpNumbersNoBars)
CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_1), (void *)(OBJ_VRAM0 + gSprites[healthBarSpriteId].oam.tileNum * TILE_SIZE_4BPP), 64);
TryAddPokeballIconToHealthbox(healthboxSpriteId, TRUE);
return;
}
pltAdder = gSprites[healthboxSpriteId].oam.paletteNum * 16;
pltAdder += battlerId + 12;
FillPalette(sStatusIconColors[statusPalId], pltAdder + 0x100, 2);
CpuCopy16(gPlttBufferUnfaded + 0x100 + pltAdder, (void*)(OBJ_PLTT + pltAdder * 2), 2);
CpuCopy32(statusGfxPtr, (void*)(OBJ_VRAM0 + (gSprites[healthboxSpriteId].oam.tileNum + tileNumAdder) * TILE_SIZE_4BPP), 96);
if (IsDoubleBattle() == TRUE || GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
{
if (!gBattleSpritesDataPtr->battlerData[battlerId].hpNumbersNoBars)
{
CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_0), (void*)(OBJ_VRAM0 + gSprites[healthBarSpriteId].oam.tileNum * TILE_SIZE_4BPP), 32);
CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_65), (void*)(OBJ_VRAM0 + (gSprites[healthBarSpriteId].oam.tileNum + 1) * TILE_SIZE_4BPP), 32);
}
}
TryAddPokeballIconToHealthbox(healthboxSpriteId, FALSE);
}
static u8 GetStatusIconForBattlerId(u8 statusElementId, u8 battlerId)
{
u8 ret = statusElementId;
switch (statusElementId)
{
case HEALTHBOX_GFX_STATUS_PSN_BATTLER0:
if (battlerId == 0)
ret = HEALTHBOX_GFX_STATUS_PSN_BATTLER0;
else if (battlerId == 1)
ret = HEALTHBOX_GFX_STATUS_PSN_BATTLER1;
else if (battlerId == 2)
ret = HEALTHBOX_GFX_STATUS_PSN_BATTLER2;
else
ret = HEALTHBOX_GFX_STATUS_PSN_BATTLER3;
break;
case HEALTHBOX_GFX_STATUS_PRZ_BATTLER0:
if (battlerId == 0)
ret = HEALTHBOX_GFX_STATUS_PRZ_BATTLER0;
else if (battlerId == 1)
ret = HEALTHBOX_GFX_STATUS_PRZ_BATTLER1;
else if (battlerId == 2)
ret = HEALTHBOX_GFX_STATUS_PRZ_BATTLER2;
else
ret = HEALTHBOX_GFX_STATUS_PRZ_BATTLER3;
break;
case HEALTHBOX_GFX_STATUS_SLP_BATTLER0:
if (battlerId == 0)
ret = HEALTHBOX_GFX_STATUS_SLP_BATTLER0;
else if (battlerId == 1)
ret = HEALTHBOX_GFX_STATUS_SLP_BATTLER1;
else if (battlerId == 2)
ret = HEALTHBOX_GFX_STATUS_SLP_BATTLER2;
else
ret = HEALTHBOX_GFX_STATUS_SLP_BATTLER3;
break;
case HEALTHBOX_GFX_STATUS_FRZ_BATTLER0:
if (battlerId == 0)
ret = HEALTHBOX_GFX_STATUS_FRZ_BATTLER0;
else if (battlerId == 1)
ret = HEALTHBOX_GFX_STATUS_FRZ_BATTLER1;
else if (battlerId == 2)
ret = HEALTHBOX_GFX_STATUS_FRZ_BATTLER2;
else
ret = HEALTHBOX_GFX_STATUS_FRZ_BATTLER3;
break;
case HEALTHBOX_GFX_STATUS_BRN_BATTLER0:
if (battlerId == 0)
ret = HEALTHBOX_GFX_STATUS_BRN_BATTLER0;
else if (battlerId == 1)
ret = HEALTHBOX_GFX_STATUS_BRN_BATTLER1;
else if (battlerId == 2)
ret = HEALTHBOX_GFX_STATUS_BRN_BATTLER2;
else
ret = HEALTHBOX_GFX_STATUS_BRN_BATTLER3;
break;
}
return ret;
}
static void UpdateSafariBallsTextOnHealthbox(u8 healthboxSpriteId)
{
u32 windowId, spriteTileNum;
u8 *windowTileData;
windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gText_SafariBalls, 0, 3, 2, &windowId);
spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum * TILE_SIZE_4BPP;
TextIntoHealthboxObject((void*)(OBJ_VRAM0 + 0x40) + spriteTileNum, windowTileData, 6);
TextIntoHealthboxObject((void*)(OBJ_VRAM0 + 0x800) + spriteTileNum, windowTileData + 0xC0, 2);
RemoveWindowOnHealthbox(windowId);
}
static void UpdateLeftNoOfBallsTextOnHealthbox(u8 healthboxSpriteId)
{
u8 text[16];
u8 *txtPtr;
u32 windowId, spriteTileNum;
u8 *windowTileData;
txtPtr = StringCopy(text, gText_SafariBallLeft);
ConvertIntToDecimalStringN(txtPtr, gNumSafariBalls, STR_CONV_MODE_LEFT_ALIGN, 2);
windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, GetStringRightAlignXOffset(0, text, 0x2F), 3, 2, &windowId);
spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum * TILE_SIZE_4BPP;
SafariTextIntoHealthboxObject((void*)(OBJ_VRAM0 + 0x2C0) + spriteTileNum, windowTileData, 2);
SafariTextIntoHealthboxObject((void*)(OBJ_VRAM0 + 0xA00) + spriteTileNum, windowTileData + 0x40, 4);
RemoveWindowOnHealthbox(windowId);
}
void UpdateHealthboxAttribute(u8 healthboxSpriteId, struct Pokemon *mon, u8 elementId)
{
s32 maxHp, currHp;
u8 battlerId = gSprites[healthboxSpriteId].hMain_Battler;
if (GetBattlerSide(gSprites[healthboxSpriteId].hMain_Battler) == B_SIDE_PLAYER)
{
u8 isDoubles;
if (elementId == HEALTHBOX_LEVEL || elementId == HEALTHBOX_ALL)
UpdateLvlInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_LEVEL));
if (elementId == HEALTHBOX_CURRENT_HP || elementId == HEALTHBOX_ALL)
UpdateHpTextInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_HP), HP_CURRENT);
if (elementId == HEALTHBOX_MAX_HP || elementId == HEALTHBOX_ALL)
UpdateHpTextInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_MAX_HP), HP_MAX);
if (elementId == HEALTHBOX_HEALTH_BAR || elementId == HEALTHBOX_ALL)
{
LoadBattleBarGfx(0);
maxHp = GetMonData(mon, MON_DATA_MAX_HP);
currHp = GetMonData(mon, MON_DATA_HP);
SetBattleBarStruct(battlerId, healthboxSpriteId, maxHp, currHp, 0);
MoveBattleBar(battlerId, healthboxSpriteId, HEALTH_BAR, 0);
}
isDoubles = IsDoubleBattle();
if (!isDoubles && (elementId == HEALTHBOX_EXP_BAR || elementId == HEALTHBOX_ALL))
{
u16 species;
u32 exp, currLevelExp;
s32 currExpBarValue, maxExpBarValue;
u8 level;
LoadBattleBarGfx(3);
species = GetMonData(mon, MON_DATA_SPECIES);
level = GetMonData(mon, MON_DATA_LEVEL);
exp = GetMonData(mon, MON_DATA_EXP);
currLevelExp = gExperienceTables[gBaseStats[species].growthRate][level];
currExpBarValue = exp - currLevelExp;
maxExpBarValue = gExperienceTables[gBaseStats[species].growthRate][level + 1] - currLevelExp;
SetBattleBarStruct(battlerId, healthboxSpriteId, maxExpBarValue, currExpBarValue, isDoubles);
MoveBattleBar(battlerId, healthboxSpriteId, EXP_BAR, 0);
}
if (elementId == HEALTHBOX_NICK || elementId == HEALTHBOX_ALL)
UpdateNickInHealthbox(healthboxSpriteId, mon);
if (elementId == HEALTHBOX_STATUS_ICON || elementId == HEALTHBOX_ALL)
UpdateStatusIconInHealthbox(healthboxSpriteId);
if (elementId == HEALTHBOX_SAFARI_ALL_TEXT)
UpdateSafariBallsTextOnHealthbox(healthboxSpriteId);
if (elementId == HEALTHBOX_SAFARI_ALL_TEXT || elementId == HEALTHBOX_SAFARI_BALLS_TEXT)
UpdateLeftNoOfBallsTextOnHealthbox(healthboxSpriteId);
}
else
{
if (elementId == HEALTHBOX_LEVEL || elementId == HEALTHBOX_ALL)
UpdateLvlInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_LEVEL));
if (gBattleSpritesDataPtr->battlerData[battlerId].hpNumbersNoBars && (elementId == HEALTHBOX_CURRENT_HP || elementId == HEALTHBOX_ALL))
UpdateHpTextInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_HP), HP_CURRENT);
if (gBattleSpritesDataPtr->battlerData[battlerId].hpNumbersNoBars && (elementId == HEALTHBOX_MAX_HP || elementId == HEALTHBOX_ALL))
UpdateHpTextInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_MAX_HP), HP_MAX);
if (elementId == HEALTHBOX_HEALTH_BAR || elementId == HEALTHBOX_ALL)
{
LoadBattleBarGfx(0);
maxHp = GetMonData(mon, MON_DATA_MAX_HP);
currHp = GetMonData(mon, MON_DATA_HP);
SetBattleBarStruct(battlerId, healthboxSpriteId, maxHp, currHp, 0);
MoveBattleBar(battlerId, healthboxSpriteId, HEALTH_BAR, 0);
}
if (elementId == HEALTHBOX_NICK || elementId == HEALTHBOX_ALL)
UpdateNickInHealthbox(healthboxSpriteId, mon);
if (elementId == HEALTHBOX_STATUS_ICON || elementId == HEALTHBOX_ALL)
UpdateStatusIconInHealthbox(healthboxSpriteId);
}
}
#define B_EXPBAR_PIXELS 64
#define B_HEALTHBAR_PIXELS 48
s32 MoveBattleBar(u8 battlerId, u8 healthboxSpriteId, u8 whichBar, u8 unused)
{
s32 currentBarValue;
if (whichBar == HEALTH_BAR) // health bar
{
currentBarValue = CalcNewBarValue(gBattleSpritesDataPtr->battleBars[battlerId].maxValue,
gBattleSpritesDataPtr->battleBars[battlerId].oldValue,
gBattleSpritesDataPtr->battleBars[battlerId].receivedValue,
&gBattleSpritesDataPtr->battleBars[battlerId].currValue,
B_HEALTHBAR_PIXELS / 8, 1);
}
else // exp bar
{
u16 expFraction = GetScaledExpFraction(gBattleSpritesDataPtr->battleBars[battlerId].oldValue,
gBattleSpritesDataPtr->battleBars[battlerId].receivedValue,
gBattleSpritesDataPtr->battleBars[battlerId].maxValue, 8);
if (expFraction == 0)
expFraction = 1;
expFraction = abs(gBattleSpritesDataPtr->battleBars[battlerId].receivedValue / expFraction);
currentBarValue = CalcNewBarValue(gBattleSpritesDataPtr->battleBars[battlerId].maxValue,
gBattleSpritesDataPtr->battleBars[battlerId].oldValue,
gBattleSpritesDataPtr->battleBars[battlerId].receivedValue,
&gBattleSpritesDataPtr->battleBars[battlerId].currValue,
B_EXPBAR_PIXELS / 8, expFraction);
}
if (whichBar == EXP_BAR || (whichBar == HEALTH_BAR && !gBattleSpritesDataPtr->battlerData[battlerId].hpNumbersNoBars))
MoveBattleBarGraphically(battlerId, whichBar);
if (currentBarValue == -1)
gBattleSpritesDataPtr->battleBars[battlerId].currValue = 0;
return currentBarValue;
}
static void MoveBattleBarGraphically(u8 battlerId, u8 whichBar)
{
u8 array[8];
u8 filledPixelsCount, level;
u8 barElementId;
u8 i;
switch (whichBar)
{
case HEALTH_BAR:
filledPixelsCount = CalcBarFilledPixels(gBattleSpritesDataPtr->battleBars[battlerId].maxValue,
gBattleSpritesDataPtr->battleBars[battlerId].oldValue,
gBattleSpritesDataPtr->battleBars[battlerId].receivedValue,
&gBattleSpritesDataPtr->battleBars[battlerId].currValue,
array, B_HEALTHBAR_PIXELS / 8);
if (filledPixelsCount > (B_HEALTHBAR_PIXELS * 50 / 100)) // more than 50 % hp
barElementId = HEALTHBOX_GFX_HP_BAR_GREEN;
else if (filledPixelsCount > (B_HEALTHBAR_PIXELS * 20 / 100)) // more than 20% hp
barElementId = HEALTHBOX_GFX_HP_BAR_YELLOW;
else
barElementId = HEALTHBOX_GFX_HP_BAR_RED; // 20 % or less
for (i = 0; i < 6; i++)
{
u8 healthbarSpriteId = gSprites[gBattleSpritesDataPtr->battleBars[battlerId].healthboxSpriteId].hMain_HealthBarSpriteId;
if (i < 2)
CpuCopy32(GetHealthboxElementGfxPtr(barElementId) + array[i] * 32,
(void*)(OBJ_VRAM0 + (gSprites[healthbarSpriteId].oam.tileNum + 2 + i) * TILE_SIZE_4BPP), 32);
else
CpuCopy32(GetHealthboxElementGfxPtr(barElementId) + array[i] * 32,
(void*)(OBJ_VRAM0 + 64 + (i + gSprites[healthbarSpriteId].oam.tileNum) * TILE_SIZE_4BPP), 32);
}
break;
case EXP_BAR:
CalcBarFilledPixels(gBattleSpritesDataPtr->battleBars[battlerId].maxValue,
gBattleSpritesDataPtr->battleBars[battlerId].oldValue,
gBattleSpritesDataPtr->battleBars[battlerId].receivedValue,
&gBattleSpritesDataPtr->battleBars[battlerId].currValue,
array, B_EXPBAR_PIXELS / 8);
level = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_LEVEL);
if (level == MAX_LEVEL)
{
for (i = 0; i < 8; i++)
array[i] = 0;
}
for (i = 0; i < 8; i++)
{
if (i < 4)
CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_12) + array[i] * 32,
(void*)(OBJ_VRAM0 + (gSprites[gBattleSpritesDataPtr->battleBars[battlerId].healthboxSpriteId].oam.tileNum + 0x24 + i) * TILE_SIZE_4BPP), 32);
else
CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_12) + array[i] * 32,
(void*)(OBJ_VRAM0 + 0xB80 + (i + gSprites[gBattleSpritesDataPtr->battleBars[battlerId].healthboxSpriteId].oam.tileNum) * TILE_SIZE_4BPP), 32);
}
break;
}
}
static s32 CalcNewBarValue(s32 maxValue, s32 oldValue, s32 receivedValue, s32 *currValue, u8 scale, u16 toAdd)
{
s32 ret, newValue;
scale *= 8;
if (*currValue == -32768) // first function call
{
if (maxValue < scale)
*currValue = Q_24_8(oldValue);
else
*currValue = oldValue;
}
newValue = oldValue - receivedValue;
if (newValue < 0)
newValue = 0;
else if (newValue > maxValue)
newValue = maxValue;
if (maxValue < scale)
{
if (newValue == Q_24_8_TO_INT(*currValue) && (*currValue & 0xFF) == 0)
return -1;
}
else
{
if (newValue == *currValue) // we're done, the bar's value has been updated
return -1;
}
if (maxValue < scale) // handle cases of max var having less pixels than the whole bar
{
s32 toAdd = Q_24_8(maxValue) / scale;
if (receivedValue < 0) // fill bar right
{
*currValue += toAdd;
ret = Q_24_8_TO_INT(*currValue);
if (ret >= newValue)
{
*currValue = Q_24_8(newValue);
ret = newValue;
}
}
else // move bar left
{
*currValue -= toAdd;
ret = Q_24_8_TO_INT(*currValue);
// try round up
if ((*currValue & 0xFF) > 0)
ret++;
if (ret <= newValue)
{
*currValue = Q_24_8(newValue);
ret = newValue;
}
}
}
else
{
if (receivedValue < 0) // fill bar right
{
*currValue += toAdd;
if (*currValue > newValue)
*currValue = newValue;
ret = *currValue;
}
else // move bar left
{
*currValue -= toAdd;
if (*currValue < newValue)
*currValue = newValue;
ret = *currValue;
}
}
return ret;
}
static u8 CalcBarFilledPixels(s32 maxValue, s32 oldValue, s32 receivedValue, s32 *currValue, u8 *arg4, u8 scale)
{
u8 pixels, filledPixels, totalPixels;
u8 i;
s32 newValue = oldValue - receivedValue;
if (newValue < 0)
newValue = 0;
else if (newValue > maxValue)
newValue = maxValue;
totalPixels = scale * 8;
for (i = 0; i < scale; i++)
arg4[i] = 0;
if (maxValue < totalPixels)
pixels = (*currValue * totalPixels / maxValue) >> 8;
else
pixels = *currValue * totalPixels / maxValue;
filledPixels = pixels;
if (filledPixels == 0 && newValue > 0)
{
arg4[0] = 1;
filledPixels = 1;
}
else
{
for (i = 0; i < scale; i++)
{
if (pixels >= 8)
{
arg4[i] = 8;
}
else
{
arg4[i] = pixels;
break;
}
pixels -= 8;
}
}
return filledPixels;
}
// These two functions seem as if they were made for testing the health bar.
static s16 sub_8074F28(struct TestingBar *barInfo, s32 *currValue, u16 *arg2, s32 arg3)
{
s16 ret, var;
ret = CalcNewBarValue(barInfo->maxValue,
barInfo->oldValue,
barInfo->receivedValue,
currValue, B_HEALTHBAR_PIXELS / 8, 1);
sub_8074F88(barInfo, currValue, arg2);
if (barInfo->maxValue < B_HEALTHBAR_PIXELS)
var = *currValue >> 8;
else
var = *currValue;
DummiedOutFunction(barInfo->maxValue, var, arg3);
return ret;
}
static void sub_8074F88(struct TestingBar *barInfo, s32 *currValue, u16 *arg2)
{
u8 sp8[6];
u16 sp10[6];
u8 i;
CalcBarFilledPixels(barInfo->maxValue, barInfo->oldValue,
barInfo->receivedValue, currValue, sp8, B_HEALTHBAR_PIXELS / 8);
for (i = 0; i < 6; i++)
sp10[i] = (barInfo->unkC_0 << 12) | (barInfo->unk10 + sp8[i]);
CpuCopy16(sp10, arg2, sizeof(sp10));
}
static u8 GetScaledExpFraction(s32 oldValue, s32 receivedValue, s32 maxValue, u8 scale)
{
s32 newVal, result;
s8 oldToMax, newToMax;
scale *= 8;
newVal = oldValue - receivedValue;
if (newVal < 0)
newVal = 0;
else if (newVal > maxValue)
newVal = maxValue;
oldToMax = oldValue * scale / maxValue;
newToMax = newVal * scale / maxValue;
result = oldToMax - newToMax;
return abs(result);
}
u8 GetScaledHPFraction(s16 hp, s16 maxhp, u8 scale)
{
u8 result = hp * scale / maxhp;
if (result == 0 && hp > 0)
return 1;
return result;
}
u8 GetHPBarLevel(s16 hp, s16 maxhp)
{
u8 result;
if (hp == maxhp)
{
result = HP_BAR_FULL;
}
else
{
u8 fraction = GetScaledHPFraction(hp, maxhp, B_HEALTHBAR_PIXELS);
if (fraction > (B_HEALTHBAR_PIXELS * 50 / 100)) // more than 50 % hp
result = HP_BAR_GREEN;
else if (fraction > (B_HEALTHBAR_PIXELS * 20 / 100)) // more than 20% hp
result = HP_BAR_YELLOW;
else if (fraction > 0)
result = HP_BAR_RED;
else
result = HP_BAR_EMPTY;
}
return result;
}
static u8* AddTextPrinterAndCreateWindowOnHealthbox(const u8 *str, u32 x, u32 y, u32 bgColor, u32 *windowId)
{
u16 winId;
u8 color[3];
struct WindowTemplate winTemplate = sHealthboxWindowTemplate;
winId = AddWindow(&winTemplate);
FillWindowPixelBuffer(winId, (bgColor << 4) | (bgColor));
color[0] = bgColor;
color[1] = 1;
color[2] = 3;
AddTextPrinterParameterized4(winId, 0, x, y, 0, 0, color, -1, str);
*windowId = winId;
return (u8*)(GetWindowAttribute(winId, WINDOW_TILE_DATA));
}
static void RemoveWindowOnHealthbox(u32 windowId)
{
RemoveWindow(windowId);
}
static void FillHealthboxObject(void *dest, u32 arg1, u32 arg2)
{
CpuFill32(0x11111111 * arg1, dest, arg2 * TILE_SIZE_4BPP);
}
static void HpTextIntoHealthboxObject(void *dest, u8 *windowTileData, u32 windowWidth)
{
CpuCopy32(windowTileData + 256, dest, windowWidth * TILE_SIZE_4BPP);
}
static void TextIntoHealthboxObject(void *dest, u8 *windowTileData, s32 windowWidth)
{
CpuCopy32(windowTileData + 256, dest + 256, windowWidth * TILE_SIZE_4BPP);
// + 256 as that prevents the top 4 blank rows of sHealthboxWindowTemplate from being copied
if (windowWidth > 0)
{
do
{
CpuCopy32(windowTileData + 20, dest + 20, 12);
dest += 32, windowTileData += 32;
windowWidth--;
} while (windowWidth != 0);
}
}
static void SafariTextIntoHealthboxObject(void *dest, u8 *windowTileData, u32 windowWidth)
{
CpuCopy32(windowTileData, dest, windowWidth * TILE_SIZE_4BPP);
CpuCopy32(windowTileData + 256, dest + 256, windowWidth * TILE_SIZE_4BPP);
}
#define ABILITY_POP_UP_TAG 0xD720
// for sprite
#define tOriginalX data[0]
#define tHide data[1]
#define tFrames data[2]
#define tRightToLeft data[3]
#define tBattlerId data[4]
#define tIsMain data[5]
// for task
#define tSpriteId1 data[6]
#define tSpriteId2 data[7]
static const u8 sAbilityPopUpGfx[] = INCBIN_U8("graphics/battle_interface/ability_pop_up.4bpp");
static const u16 sAbilityPopUpPalette[] = INCBIN_U16("graphics/battle_interface/ability_pop_up.gbapal");
static const struct SpriteSheet sSpriteSheet_AbilityPopUp =
{
sAbilityPopUpGfx, sizeof(sAbilityPopUpGfx), ABILITY_POP_UP_TAG
};
static const struct SpritePalette sSpritePalette_AbilityPopUp =
{
sAbilityPopUpPalette, ABILITY_POP_UP_TAG
};
static const struct OamData sOamData_AbilityPopUp =
{
.y = 0,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 0,
.shape = ST_OAM_H_RECTANGLE,
.x = 0,
.matrixNum = 0,
.size = 3,
.tileNum = 0,
.priority = 0,
.paletteNum = 0,
.affineParam = 0,
};
static const union AnimCmd sSpriteAnim_AbilityPopUp1[] =
{
ANIMCMD_FRAME(0, 0),
ANIMCMD_END
};
static const union AnimCmd *const sSpriteAnimTable_AbilityPopUp1[] =
{
sSpriteAnim_AbilityPopUp1
};
static const struct SpriteTemplate sSpriteTemplate_AbilityPopUp1 =
{
.tileTag = ABILITY_POP_UP_TAG,
.paletteTag = ABILITY_POP_UP_TAG,
.oam = &sOamData_AbilityPopUp,
.anims = sSpriteAnimTable_AbilityPopUp1,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCb_AbilityPopUp
};
static const union AnimCmd sSpriteAnim_AbilityPopUp2[] =
{
ANIMCMD_FRAME(32, 0),
ANIMCMD_END
};
static const union AnimCmd *const sSpriteAnimTable_AbilityPopUp2[] =
{
sSpriteAnim_AbilityPopUp2
};
static const struct SpriteTemplate sSpriteTemplate_AbilityPopUp2 =
{
.tileTag = ABILITY_POP_UP_TAG,
.paletteTag = ABILITY_POP_UP_TAG,
.oam = &sOamData_AbilityPopUp,
.anims = sSpriteAnimTable_AbilityPopUp2,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCb_AbilityPopUp
};
#define ABILITY_POP_UP_POS_X_DIFF 64
#define ABILITY_POP_UP_POS_X_SLIDE 68
static const s16 sAbilityPopUpCoordsDoubles[MAX_BATTLERS_COUNT][2] =
{
{29, 80}, // player left
{204, 19}, // opponent left
{29, 97}, // player right
{204, 36}, // opponent right
};
static const s16 sAbilityPopUpCoordsSingles[MAX_BATTLERS_COUNT][2] =
{
{29, 93}, // player
{204, 23}, // opponent
};
static u8* AddTextPrinterAndCreateWindowOnAbilityPopUp(const u8 *str, u32 x, u32 y, u32 color1, u32 color2, u32 color3, u32 *windowId)
{
u8 color[3] = {color1, color2, color3};
struct WindowTemplate winTemplate = {0};
winTemplate.width = 8;
winTemplate.height = 2;
*windowId = AddWindow(&winTemplate);
FillWindowPixelBuffer(*windowId, (color1 << 4) | (color1));
AddTextPrinterParameterized4(*windowId, 0, x, y, 0, 0, color, -1, str);
return (u8*)(GetWindowAttribute(*windowId, WINDOW_TILE_DATA));
}
static void TextIntoAbilityPopUp(void *dest, u8 *windowTileData, s32 arg2, bool32 arg3)
{
CpuCopy32(windowTileData + 256, dest + 256, arg2 * 32);
if (arg2 > 0)
{
do
{
if (arg3)
CpuCopy32(windowTileData + 16, dest + 16, 16);
else
CpuCopy32(windowTileData + 20, dest + 20, 12);
dest += 32, windowTileData += 32;
arg2--;
} while (arg2 != 0);
}
}
#define MAX_CHARS_PRINTED 12
static void PrintOnAbilityPopUp(const u8 *str, u8 *spriteTileData1, u8 *spriteTileData2, u32 x1, u32 x2, u32 y, u32 color1, u32 color2, u32 color3)
{
u32 windowId, i;
u8 *windowTileData;
u8 text1[MAX_CHARS_PRINTED + 1];
u8 text2[MAX_CHARS_PRINTED + 1];
for (i = 0; i < MAX_CHARS_PRINTED + 1; i++)
{
text1[i] = str[i];
if (text1[i] == EOS)
break;
}
text1[i] = EOS;
windowTileData = AddTextPrinterAndCreateWindowOnAbilityPopUp(text1, x1, y, color1, color2, color3, &windowId);
TextIntoAbilityPopUp(spriteTileData1, windowTileData, 8, (y == 0));
RemoveWindow(windowId);
if (i == MAX_CHARS_PRINTED + 1)
{
for (i = 0; i < MAX_CHARS_PRINTED; i++)
{
text2[i] = str[MAX_CHARS_PRINTED + i];
if (text2[i] == EOS)
break;
}
text2[i] = EOS;
windowTileData = AddTextPrinterAndCreateWindowOnAbilityPopUp(text2, x2, y, color1, color2, color3, &windowId);
TextIntoAbilityPopUp(spriteTileData2, windowTileData, 1, (y == 0));
RemoveWindow(windowId);
}
}
static void PrintBattlerOnAbilityPopUp(u8 battlerId, u8 spriteId1, u8 spriteId2)
{
PrintOnAbilityPopUp(gBattleMons[battlerId].nickname,
(void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32),
(void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32),
7, 0,
0,
2, 7, 1);
}
static void PrintAbilityOnAbilityPopUp(u32 ability, u8 spriteId1, u8 spriteId2)
{
PrintOnAbilityPopUp(gAbilityNames[ability],
(void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32) + 256,
(void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32) + 256,
7, 1,
4,
7, 9, 1);
}
#define PIXEL_COORDS_TO_OFFSET(x, y)( \
/*Add tiles by X*/ \
((y / 8) * 32 * 8) \
/*Add tiles by X*/ \
+ ((x / 8) * 32) \
/*Add pixels by Y*/ \
+ ((((y) - ((y / 8) * 8))) * 4) \
/*Add pixels by X*/ \
+ ((((x) - ((x / 8) * 8)) / 2)))
static const u16 sOverwrittenPixelsTable[][2] =
{
{PIXEL_COORDS_TO_OFFSET(0, 0), 5},
{PIXEL_COORDS_TO_OFFSET(0, 1), 5},
{PIXEL_COORDS_TO_OFFSET(0, 2), 5},
{PIXEL_COORDS_TO_OFFSET(0, 3), 5},
{PIXEL_COORDS_TO_OFFSET(0, 4), 5},
{PIXEL_COORDS_TO_OFFSET(0, 5), 5},
{PIXEL_COORDS_TO_OFFSET(0, 6), 5},
{PIXEL_COORDS_TO_OFFSET(0, 7), 3},
{PIXEL_COORDS_TO_OFFSET(0, 8), 3},
{PIXEL_COORDS_TO_OFFSET(0, 9), 3},
{PIXEL_COORDS_TO_OFFSET(0, 10), 3},
{PIXEL_COORDS_TO_OFFSET(0, 11), 3},
{PIXEL_COORDS_TO_OFFSET(0, 12), 3},
{PIXEL_COORDS_TO_OFFSET(0, 13), 8},
{PIXEL_COORDS_TO_OFFSET(8, 13), 8},
{PIXEL_COORDS_TO_OFFSET(16, 13), 8},
{PIXEL_COORDS_TO_OFFSET(24, 13), 8},
{PIXEL_COORDS_TO_OFFSET(32, 13), 8},
{PIXEL_COORDS_TO_OFFSET(40, 13), 8},
{PIXEL_COORDS_TO_OFFSET(48, 13), 8},
{PIXEL_COORDS_TO_OFFSET(56, 13), 8},
{PIXEL_COORDS_TO_OFFSET(0, 14), 8},
{PIXEL_COORDS_TO_OFFSET(8, 14), 8},
{PIXEL_COORDS_TO_OFFSET(16, 14), 8},
{PIXEL_COORDS_TO_OFFSET(24, 14), 8},
{PIXEL_COORDS_TO_OFFSET(32, 14), 8},
{PIXEL_COORDS_TO_OFFSET(40, 14), 8},
{PIXEL_COORDS_TO_OFFSET(48, 14), 8},
{PIXEL_COORDS_TO_OFFSET(56, 14), 8},
{PIXEL_COORDS_TO_OFFSET(0, 15), 3},
{PIXEL_COORDS_TO_OFFSET(0, 16), 3},
{PIXEL_COORDS_TO_OFFSET(0, 17), 3},
{PIXEL_COORDS_TO_OFFSET(0, 18), 3},
{PIXEL_COORDS_TO_OFFSET(0, 19), 3},
{PIXEL_COORDS_TO_OFFSET(0, 20), 3},
{PIXEL_COORDS_TO_OFFSET(0, 21), 3},
{PIXEL_COORDS_TO_OFFSET(0, 22), 3},
{PIXEL_COORDS_TO_OFFSET(0, 23), 3},
{PIXEL_COORDS_TO_OFFSET(0, 24), 3},
{PIXEL_COORDS_TO_OFFSET(0, 25), 3},
{PIXEL_COORDS_TO_OFFSET(0, 26), 3},
};
static inline void CopyPixels(u8 *dest, const u8 *src, u32 pixelCount)
{
u32 i = 0;
if (pixelCount & 1)
{
while (pixelCount != 0)
{
dest[i] &= ~(0xF);
dest[i] |= (src[i] & 0xF);
if (--pixelCount != 0)
{
dest[i] &= ~(0xF0);
dest[i] |= (src[i] & 0xF0);
pixelCount--;
}
i++;
}
}
else
{
for (i = 0; i < pixelCount / 2; i++)
dest[i] = src[i];
}
}
static void RestoreOverwrittenPixels(u8 *tiles)
{
u32 i;
u8 *buffer = Alloc(sizeof(sAbilityPopUpGfx) * 2);
CpuCopy32(tiles, buffer, sizeof(sAbilityPopUpGfx));
for (i = 0; i < ARRAY_COUNT(sOverwrittenPixelsTable); i++)
{
CopyPixels(buffer + sOverwrittenPixelsTable[i][0],
sAbilityPopUpGfx + sOverwrittenPixelsTable[i][0],
sOverwrittenPixelsTable[i][1]);
}
CpuCopy32(buffer, tiles, sizeof(sAbilityPopUpGfx));
Free(buffer);
}
void CreateAbilityPopUp(u8 battlerId, u32 ability, bool32 isDoubleBattle)
{
const s16 (*coords)[2];
u8 spriteId1, spriteId2, battlerPosition, taskId;
if (B_ABILITY_POP_UP < GEN_5)
return;
if (!gBattleStruct->activeAbilityPopUps)
{
LoadSpriteSheet(&sSpriteSheet_AbilityPopUp);
LoadSpritePalette(&sSpritePalette_AbilityPopUp);
}
gBattleStruct->activeAbilityPopUps |= gBitTable[battlerId];
battlerPosition = GetBattlerPosition(battlerId);
if (isDoubleBattle)
coords = sAbilityPopUpCoordsDoubles;
else
coords = sAbilityPopUpCoordsSingles;
if ((battlerPosition & BIT_SIDE) == B_SIDE_PLAYER)
{
spriteId1 = CreateSprite(&sSpriteTemplate_AbilityPopUp1,
coords[battlerPosition][0] - ABILITY_POP_UP_POS_X_SLIDE,
coords[battlerPosition][1], 0);
spriteId2 = CreateSprite(&sSpriteTemplate_AbilityPopUp2,
coords[battlerPosition][0] - ABILITY_POP_UP_POS_X_SLIDE + ABILITY_POP_UP_POS_X_DIFF,
coords[battlerPosition][1], 0);
gSprites[spriteId1].tOriginalX = coords[battlerPosition][0];
gSprites[spriteId2].tOriginalX = coords[battlerPosition][0] + ABILITY_POP_UP_POS_X_DIFF;
gSprites[spriteId1].tRightToLeft = TRUE;
gSprites[spriteId2].tRightToLeft = TRUE;
}
else
{
spriteId1 = CreateSprite(&sSpriteTemplate_AbilityPopUp1,
coords[battlerPosition][0] + ABILITY_POP_UP_POS_X_SLIDE,
coords[battlerPosition][1], 0);
spriteId2 = CreateSprite(&sSpriteTemplate_AbilityPopUp2,
coords[battlerPosition][0] + ABILITY_POP_UP_POS_X_SLIDE + ABILITY_POP_UP_POS_X_DIFF,
coords[battlerPosition][1], 0);
gSprites[spriteId1].tOriginalX = coords[battlerPosition][0];
gSprites[spriteId2].tOriginalX = coords[battlerPosition][0] + ABILITY_POP_UP_POS_X_DIFF;
gSprites[spriteId1].tRightToLeft = FALSE;
gSprites[spriteId2].tRightToLeft = FALSE;
}
taskId = CreateTask(Task_FreeAbilityPopUpGfx, 5);
gTasks[taskId].tSpriteId1 = spriteId1;
gTasks[taskId].tSpriteId2 = spriteId2;
gSprites[spriteId1].tIsMain = TRUE;
gSprites[spriteId1].tBattlerId = battlerId;
gSprites[spriteId2].tBattlerId = battlerId;
StartSpriteAnim(&gSprites[spriteId1], 0);
StartSpriteAnim(&gSprites[spriteId2], 0);
PrintBattlerOnAbilityPopUp(battlerId, spriteId1, spriteId2);
PrintAbilityOnAbilityPopUp(ability, spriteId1, spriteId2);
RestoreOverwrittenPixels((void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32));
}
#define FRAMES_TO_WAIT 48
static void SpriteCb_AbilityPopUp(struct Sprite *sprite)
{
if (!sprite->tHide) // Show
{
if (sprite->tIsMain && ++sprite->tFrames == 4)
PlaySE(SE_SELECT);
if ((!sprite->tRightToLeft && (sprite->pos1.x -= 4) <= sprite->tOriginalX)
|| (sprite->tRightToLeft && (sprite->pos1.x += 4) >= sprite->tOriginalX)
)
{
sprite->pos1.x = sprite->tOriginalX;
sprite->tHide = TRUE;
sprite->tFrames = FRAMES_TO_WAIT;
}
}
else // Hide
{
if (sprite->tFrames == 0)
{
if ((!sprite->tRightToLeft && (sprite->pos1.x += 4) >= sprite->tOriginalX + ABILITY_POP_UP_POS_X_SLIDE)
||(sprite->tRightToLeft && (sprite->pos1.x -= 4) <= sprite->tOriginalX - ABILITY_POP_UP_POS_X_SLIDE)
)
{
gBattleStruct->activeAbilityPopUps &= ~(gBitTable[sprite->tBattlerId]);
DestroySprite(sprite);
}
}
else
{
sprite->tFrames--;
}
}
}
static void Task_FreeAbilityPopUpGfx(u8 taskId)
{
if (!gSprites[gTasks[taskId].tSpriteId1].inUse
&& !gSprites[gTasks[taskId].tSpriteId2].inUse
&& !gBattleStruct->activeAbilityPopUps)
{
FreeSpriteTilesByTag(ABILITY_POP_UP_TAG);
FreeSpritePaletteByTag(ABILITY_POP_UP_TAG);
DestroyTask(taskId);
}
}