summaryrefslogtreecommitdiff
path: root/src/battle_interface.c
diff options
context:
space:
mode:
authorGriffinR <griffin.g.richards@gmail.com>2020-01-12 15:39:21 -0500
committerGriffinR <griffin.g.richards@gmail.com>2020-01-12 16:03:06 -0500
commitf2763832931127fc24e7cb9f9cdd85e3cf706a5c (patch)
treed23050509231d1d9c6d1694b2755c93fdaf26a4e /src/battle_interface.c
parentaa84a1d3a11c7cc6fd0e1021e1ed060e0c5683f2 (diff)
parent15ff7eb2f87032797f6ce9ef9bb471c468b48a36 (diff)
Merge master into sync-script
Diffstat (limited to 'src/battle_interface.c')
-rw-r--r--src/battle_interface.c2800
1 files changed, 2800 insertions, 0 deletions
diff --git a/src/battle_interface.c b/src/battle_interface.c
new file mode 100644
index 000000000..6d16c0902
--- /dev/null
+++ b/src/battle_interface.c
@@ -0,0 +1,2800 @@
+#include "global.h"
+#include "battle_anim.h"
+#include "battle_interface.h"
+#include "battle_message.h"
+#include "decompress.h"
+#include "gpu_regs.h"
+#include "graphics.h"
+#include "menu.h"
+#include "palette.h"
+#include "pokedex.h"
+#include "pokemon_summary_screen.h"
+#include "safari_zone.h"
+#include "sound.h"
+#include "string_util.h"
+#include "strings.h"
+#include "text.h"
+#include "window.h"
+#include "constants/songs.h"
+
+#define GetStringRightAlignXOffset(fontId, string, destWidth) ({ \
+ s32 w = GetStringWidth(fontId, string, 0); \
+ destWidth - w; \
+})
+
+#define abs(a) ((a) < 0 ? -(a) : (a))
+
+#define Q_24_8(n) ((s32)((n) * 256))
+#define Q_24_8_TO_INT(n) ((int)((n) >> 8))
+
+struct TestingBar
+{
+ s32 maxValue;
+ s32 oldValue;
+ s32 receivedValue;
+ u32 pal:5;
+ u32 tileOffset;
+};
+
+enum
+{ // Corresponds to gHealthboxElementsGfxTable (and the tables after it) in graphics.c
+ // These are indexes into the tables, which are filled with 8x8 square pixel data.
+ HEALTHBOX_GFX_0, //hp bar [black section]
+ HEALTHBOX_GFX_1, //hp bar "H"
+ HEALTHBOX_GFX_2, //hp bar "P"
+ HEALTHBOX_GFX_HP_BAR_GREEN, //hp bar [0 pixels]
+ HEALTHBOX_GFX_4, //hp bar [1 pixels]
+ HEALTHBOX_GFX_5, //hp bar [2 pixels]
+ HEALTHBOX_GFX_6, //hp bar [3 pixels]
+ HEALTHBOX_GFX_7, //hp bar [4 pixels]
+ HEALTHBOX_GFX_8, //hp bar [5 pixels]
+ HEALTHBOX_GFX_9, //hp bar [6 pixels]
+ HEALTHBOX_GFX_10, //hp bar [7 pixels]
+ HEALTHBOX_GFX_11, //hp bar [8 pixels]
+ HEALTHBOX_GFX_12, //exp bar [0 pixels]
+ HEALTHBOX_GFX_13, //exp bar [1 pixels]
+ HEALTHBOX_GFX_14, //exp bar [2 pixels]
+ HEALTHBOX_GFX_15, //exp bar [3 pixels]
+ HEALTHBOX_GFX_16, //exp bar [4 pixels]
+ HEALTHBOX_GFX_17, //exp bar [5 pixels]
+ HEALTHBOX_GFX_18, //exp bar [6 pixels]
+ HEALTHBOX_GFX_19, //exp bar [7 pixels]
+ HEALTHBOX_GFX_20, //exp bar [8 pixels]
+ HEALTHBOX_GFX_STATUS_PSN_BATTLER0, //status psn "(P"
+ HEALTHBOX_GFX_22, //status psn "SN"
+ HEALTHBOX_GFX_23, //status psn "|)""
+ HEALTHBOX_GFX_STATUS_PRZ_BATTLER0, //status prz
+ HEALTHBOX_GFX_25,
+ HEALTHBOX_GFX_26,
+ HEALTHBOX_GFX_STATUS_SLP_BATTLER0, //status slp
+ HEALTHBOX_GFX_28,
+ HEALTHBOX_GFX_29,
+ HEALTHBOX_GFX_STATUS_FRZ_BATTLER0, //status frz
+ HEALTHBOX_GFX_31,
+ HEALTHBOX_GFX_32,
+ HEALTHBOX_GFX_STATUS_BRN_BATTLER0, //status brn
+ HEALTHBOX_GFX_34,
+ HEALTHBOX_GFX_35,
+ HEALTHBOX_GFX_36, //misc [Black section]
+ HEALTHBOX_GFX_37, //misc [Black section]
+ HEALTHBOX_GFX_38, //misc [Black section]
+ HEALTHBOX_GFX_39, //misc [Blank Health Window?]
+ HEALTHBOX_GFX_40, //misc [Blank Health Window?]
+ HEALTHBOX_GFX_41, //misc [Blank Health Window?]
+ HEALTHBOX_GFX_42, //misc [Blank Health Window?]
+ HEALTHBOX_GFX_43, //misc [Top of Health Window?]
+ HEALTHBOX_GFX_44, //misc [Top of Health Window?]
+ HEALTHBOX_GFX_45, //misc [Top of Health Window?]
+ HEALTHBOX_GFX_46, //misc [Blank Health Window?]
+ HEALTHBOX_GFX_HP_BAR_YELLOW, //hp bar yellow [0 pixels]
+ HEALTHBOX_GFX_48, //hp bar yellow [1 pixels]
+ HEALTHBOX_GFX_49, //hp bar yellow [2 pixels]
+ HEALTHBOX_GFX_50, //hp bar yellow [3 pixels]
+ HEALTHBOX_GFX_51, //hp bar yellow [4 pixels]
+ HEALTHBOX_GFX_52, //hp bar yellow [5 pixels]
+ HEALTHBOX_GFX_53, //hp bar yellow [6 pixels]
+ HEALTHBOX_GFX_54, //hp bar yellow [7 pixels]
+ HEALTHBOX_GFX_55, //hp bar yellow [8 pixels]
+ HEALTHBOX_GFX_HP_BAR_RED, //hp bar red [0 pixels]
+ HEALTHBOX_GFX_57, //hp bar red [1 pixels]
+ HEALTHBOX_GFX_58, //hp bar red [2 pixels]
+ HEALTHBOX_GFX_59, //hp bar red [3 pixels]
+ HEALTHBOX_GFX_60, //hp bar red [4 pixels]
+ HEALTHBOX_GFX_61, //hp bar red [5 pixels]
+ HEALTHBOX_GFX_62, //hp bar red [6 pixels]
+ HEALTHBOX_GFX_63, //hp bar red [7 pixels]
+ HEALTHBOX_GFX_64, //hp bar red [8 pixels]
+ HEALTHBOX_GFX_65, //hp bar frame end
+ HEALTHBOX_GFX_66, //status ball [full]
+ HEALTHBOX_GFX_67, //status ball [empty]
+ HEALTHBOX_GFX_68, //status ball [fainted]
+ HEALTHBOX_GFX_69, //status ball [statused]
+ HEALTHBOX_GFX_70, //status ball [unused extra]
+ HEALTHBOX_GFX_STATUS_PSN_BATTLER1, //status2 "PSN"
+ HEALTHBOX_GFX_72,
+ HEALTHBOX_GFX_73,
+ HEALTHBOX_GFX_STATUS_PRZ_BATTLER1, //status2 "PRZ"
+ HEALTHBOX_GFX_75,
+ HEALTHBOX_GFX_76,
+ HEALTHBOX_GFX_STATUS_SLP_BATTLER1, //status2 "SLP"
+ HEALTHBOX_GFX_78,
+ HEALTHBOX_GFX_79,
+ HEALTHBOX_GFX_STATUS_FRZ_BATTLER1, //status2 "FRZ"
+ HEALTHBOX_GFX_81,
+ HEALTHBOX_GFX_82,
+ HEALTHBOX_GFX_STATUS_BRN_BATTLER1, //status2 "BRN"
+ HEALTHBOX_GFX_84,
+ HEALTHBOX_GFX_85,
+ HEALTHBOX_GFX_STATUS_PSN_BATTLER2, //status3 "PSN"
+ HEALTHBOX_GFX_87,
+ HEALTHBOX_GFX_88,
+ HEALTHBOX_GFX_STATUS_PRZ_BATTLER2, //status3 "PRZ"
+ HEALTHBOX_GFX_90,
+ HEALTHBOX_GFX_91,
+ HEALTHBOX_GFX_STATUS_SLP_BATTLER2, //status3 "SLP"
+ HEALTHBOX_GFX_93,
+ HEALTHBOX_GFX_94,
+ HEALTHBOX_GFX_STATUS_FRZ_BATTLER2, //status3 "FRZ"
+ HEALTHBOX_GFX_96,
+ HEALTHBOX_GFX_97,
+ HEALTHBOX_GFX_STATUS_BRN_BATTLER2, //status3 "BRN"
+ HEALTHBOX_GFX_99,
+ HEALTHBOX_GFX_100,
+ HEALTHBOX_GFX_STATUS_PSN_BATTLER3, //status4 "PSN"
+ HEALTHBOX_GFX_102,
+ HEALTHBOX_GFX_103,
+ HEALTHBOX_GFX_STATUS_PRZ_BATTLER3, //status4 "PRZ"
+ HEALTHBOX_GFX_105,
+ HEALTHBOX_GFX_106,
+ HEALTHBOX_GFX_STATUS_SLP_BATTLER3, //status4 "SLP"
+ HEALTHBOX_GFX_108,
+ HEALTHBOX_GFX_109,
+ HEALTHBOX_GFX_STATUS_FRZ_BATTLER3, //status4 "FRZ"
+ HEALTHBOX_GFX_111,
+ HEALTHBOX_GFX_112,
+ HEALTHBOX_GFX_STATUS_BRN_BATTLER3, //status4 "BRN"
+ HEALTHBOX_GFX_114,
+ HEALTHBOX_GFX_115,
+ HEALTHBOX_GFX_116, //unknown_D12FEC
+ HEALTHBOX_GFX_117, //unknown_D1300C
+};
+
+static void SpriteCB_HealthBoxOther(struct Sprite * sprite);
+static void SpriteCB_HealthBar(struct Sprite * sprite);
+static const u8 *GetHealthboxElementGfxPtr(u8 which);
+static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent);
+static void sub_8049388(u8 taskId);
+static void sub_80493E4(u8 taskId);
+static void sub_8049568(struct Sprite * sprite);
+static void sub_8049630(struct Sprite * sprite);
+static void sub_804948C(u8 taskId);
+static void SpriteCB_StatusSummaryBallsOnSwitchout(struct Sprite * sprite);
+static void UpdateStatusIconInHealthbox(u8 spriteId);
+static void SpriteCB_StatusSummaryBar(struct Sprite * sprite);
+static void SpriteCB_StatusSummaryBallsOnBattleStart(struct Sprite * sprite);
+static u8 GetStatusIconForBattlerId(u8 statusElementId, u8 battlerId);
+static void MoveBattleBarGraphically(u8 battlerId, u8 whichBar);
+static u8 GetScaledExpFraction(s32 oldValue, s32 receivedValue, s32 maxValue, u8 scale);
+static u8 CalcBarFilledPixels(s32 maxValue, s32 oldValue, s32 receivedValue, s32 *currValue, u8 *arg4, u8 scale);
+static s32 CalcNewBarValue(s32 maxValue, s32 currValue, s32 receivedValue, s32 *arg3, u8 arg4, u16 arg5);
+static void sub_804A510(struct TestingBar *barInfo, s32 *currValue, u8 bg, u8 x, u8 y);
+static void SafariTextIntoHealthboxObject(void *dest, u8 *windowTileData, u32 windowWidth);
+static u8 *AddTextPrinterAndCreateWindowOnHealthbox(const u8 *str, u32 x, u32 y, u32 *windowId);
+static void RemoveWindowOnHealthbox(u32 windowId);
+static void TextIntoHealthboxObject(void *dest, u8 *windowTileData, s32 windowWidth);
+
+static const struct OamData gOamData_8260270 = {
+ .shape = SPRITE_SHAPE(64x32),
+ .size = SPRITE_SIZE(64x32),
+ .priority = 1
+};
+
+static const struct SpriteTemplate sHealthboxPlayerSpriteTemplates[] = {
+ {
+ .tileTag = 55039,
+ .paletteTag = 55039,
+ .oam = &gOamData_8260270,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy
+ }, {
+ .tileTag = 55040,
+ .paletteTag = 55039,
+ .oam = &gOamData_8260270,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy
+ }
+};
+
+static const struct SpriteTemplate sHealthboxOpponentSpriteTemplates[] = {
+ {
+ .tileTag = 55041,
+ .paletteTag = 55039,
+ .oam = &gOamData_8260270,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy
+ }, {
+ .tileTag = 55042,
+ .paletteTag = 55039,
+ .oam = &gOamData_8260270,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy
+ }
+};
+
+static const struct SpriteTemplate sHealthboxSafariSpriteTemplate =
+{
+ .tileTag = 55051,
+ .paletteTag = 55039,
+ .oam = &gOamData_8260270,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy
+};
+
+static const struct OamData gUnknown_82602F0 = {
+ .shape = SPRITE_SHAPE(32x8),
+ .size = SPRITE_SIZE(32x8),
+ .priority = 1
+};
+
+static const struct SpriteTemplate gUnknown_82602F8[] = {
+ {
+ .tileTag = 55044,
+ .paletteTag = 55044,
+ .oam = &gUnknown_82602F0,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_HealthBar
+ }, {
+ .tileTag = 55045,
+ .paletteTag = 55044,
+ .oam = &gUnknown_82602F0,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_HealthBar
+ }, {
+ .tileTag = 55046,
+ .paletteTag = 55044,
+ .oam = &gUnknown_82602F0,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_HealthBar
+ }, {
+ .tileTag = 55047,
+ .paletteTag = 55044,
+ .oam = &gUnknown_82602F0,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_HealthBar
+ }
+};
+
+static const struct Subsprite gUnknown_8260358[] = {
+ { 240, 0, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), 0x0000, 1 },
+ { 48, 0, SPRITE_SHAPE(32x32), SPRITE_SIZE(32x32), 0x0020, 1 },
+ { 240, 32, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0030, 1 },
+ { 16, 32, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0034, 1 },
+ { 48, 32, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0038, 1 }
+};
+
+static const struct Subsprite gUnknown_826036C[] = {
+ { 240, 0, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), 0x0040, 1 },
+ { 48, 0, SPRITE_SHAPE(32x32), SPRITE_SIZE(32x32), 0x0060, 1 },
+ { 240, 32, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0070, 1 },
+ { 16, 32, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0074, 1 },
+ { 48, 32, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0078, 1 }
+};
+
+static const struct Subsprite gUnknown_8260380[] = {
+ { 240, 0, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), 0x0000, 1 },
+ { 48, 0, SPRITE_SHAPE(32x32), SPRITE_SIZE(32x32), 0x0020, 1 }
+};
+
+static const struct Subsprite gUnknown_8260388[] = {
+ { 240, 0, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), 0x0000, 1 },
+ { 48, 0, SPRITE_SHAPE(32x32), SPRITE_SIZE(32x32), 0x0020, 1 }
+};
+
+static const struct Subsprite gUnknown_8260390[] = {
+ { 240, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0000, 1 },
+ { 16, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0004, 1 }
+};
+
+static const struct Subsprite gUnknown_8260398[] = {
+ { 240, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0000, 1 },
+ { 16, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0004, 1 },
+ { 224, 0, SPRITE_SHAPE(8x8), SPRITE_SIZE(8x8), 0x0008, 1 }
+};
+
+static const struct SubspriteTable gUnknown_82603A4[] = {
+ {NELEMS(gUnknown_8260358), gUnknown_8260358},
+ {NELEMS(gUnknown_8260380), gUnknown_8260380},
+ {NELEMS(gUnknown_826036C), gUnknown_826036C},
+ {NELEMS(gUnknown_8260388), gUnknown_8260388}
+};
+
+static const struct SubspriteTable gUnknown_82603C4[] = {
+ {NELEMS(gUnknown_8260390), gUnknown_8260390},
+ {NELEMS(gUnknown_8260398), gUnknown_8260398}
+};
+
+static const struct Subsprite gUnknown_82603D4[] = {
+ { 160, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0000, 1 },
+ { 192, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0004, 1 },
+ { 224, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0008, 1 },
+ { 0, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x000c, 1 }
+};
+
+static const struct Subsprite gUnknown_82603E4[] = {
+ { 160, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0000, 1 },
+ { 192, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0004, 1 },
+ { 224, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0008, 1 },
+ { 0, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0008, 1 },
+ { 32, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x0008, 1 },
+ { 64, 0, SPRITE_SHAPE(32x8), SPRITE_SIZE(32x8), 0x000c, 1 }
+};
+
+static const struct SubspriteTable sStatusSummaryBar_SubspriteTable[] =
+{
+ {NELEMS(gUnknown_82603D4), gUnknown_82603D4}
+};
+
+static const struct SubspriteTable gUnknown_8260404[] = {
+ {NELEMS(gUnknown_82603E4), gUnknown_82603E4}
+};
+
+static const u16 gUnknown_26040C[] = INCBIN_U16("graphics/battle_interface/unk_826404C.4bpp");
+
+static const struct CompressedSpriteSheet sStatusSummaryBarSpriteSheets[] = {
+ {gFile_graphics_battle_interface_ball_status_bar_sheet, 0x0200, 55052},
+ {gFile_graphics_battle_interface_ball_status_bar_sheet, 0x0200, 55053}
+};
+
+static const struct SpritePalette sStatusSummaryBarSpritePals[] = {
+ {gBattleInterface_BallStatusBarPal, 55056},
+ {gBattleInterface_BallStatusBarPal, 55057}
+};
+
+static const struct SpritePalette sStatusSummaryBallsSpritePals[] = {
+ {gBattleInterface_BallDisplayPal, 55058},
+ {gBattleInterface_BallDisplayPal, 55059}
+};
+
+static const struct SpriteSheet sStatusSummaryBallsSpriteSheets[] = {
+ {gUnknown_8D12404, 0x0080, 55060},
+ {gUnknown_8D12404, 0x0080, 55061}
+};
+
+static const struct OamData gUnknown_82604AC = {
+ .shape = SPRITE_SHAPE(64x32),
+ .size = SPRITE_SIZE(64x32),
+ .priority = 1
+};
+
+static const struct OamData gUnknown_82604B4 = {
+ .shape = SPRITE_SHAPE(8x8),
+ .size = SPRITE_SIZE(8x8),
+ .priority = 1
+};
+
+static const struct SpriteTemplate sStatusSummaryBarSpriteTemplates[] = {
+ {
+ .tileTag = 55052,
+ .paletteTag = 55056,
+ .oam = &gOamData_8260270,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_StatusSummaryBar
+ }, {
+ .tileTag = 55053,
+ .paletteTag = 55057,
+ .oam = &gOamData_8260270,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_StatusSummaryBar
+ }
+};
+
+static const struct SpriteTemplate sStatusSummaryBallsSpriteTemplates[] = {
+ {
+ .tileTag = 55060,
+ .paletteTag = 55058,
+ .oam = &gUnknown_82604B4,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_StatusSummaryBallsOnBattleStart
+ }, {
+ .tileTag = 55061,
+ .paletteTag = 55059,
+ .oam = &gUnknown_82604B4,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_StatusSummaryBallsOnBattleStart
+ }
+};
+
+static void sub_8047B0C(s16 number, u16 *dest, bool8 unk)
+{
+ s8 i, j;
+ u8 buff[4];
+
+ for (i = 0; i < 4; i++)
+ {
+ buff[i] = 0;
+ }
+
+ for (i = 3; ; i--)
+ {
+ if (number > 0)
+ {
+ buff[i] = number % 10;
+ number /= 10;
+ }
+ else
+ {
+ for (; i > -1; i--)
+ {
+ buff[i] = 0xFF;
+ }
+ if (buff[3] == 0xFF)
+ buff[3] = 0;
+ break;
+ }
+ }
+
+
+
+ if (!unk)
+ {
+ for (i = 0, j = 0; i < 4; i++)
+ {
+ if (buff[j] == 0xFF)
+ {
+ dest[j + 0x00] &= 0xFC00;
+ dest[j + 0x00] |= 0x1E;
+ dest[i + 0x20] &= 0xFC00;
+ dest[i + 0x20] |= 0x1E;
+ }
+ else
+ {
+ dest[j + 0x00] &= 0xFC00;
+ dest[j + 0x00] |= 0x14 + buff[j];
+ dest[i + 0x20] &= 0xFC00;
+ dest[i + 0x20] |= 0x34 + buff[i];
+ }
+ j++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 4; i++)
+ {
+ if (buff[i] == 0xFF)
+ {
+ dest[i + 0x00] &= 0xFC00;
+ dest[i + 0x00] |= 0x1E;
+ dest[i + 0x20] &= 0xFC00;
+ dest[i + 0x20] |= 0x1E;
+ }
+ else
+ {
+ dest[i + 0x00] &= 0xFC00;
+ dest[i + 0x00] |= 0x14 + buff[i];
+ dest[i + 0x20] &= 0xFC00;
+ dest[i + 0x20] |= 0x34 + buff[i];
+ }
+ }
+ }
+}
+
+static void sub_8047CAC(s16 num1, s16 num2, u16 *dest)
+{
+ dest[4] = 0x1E;
+ sub_8047B0C(num2, &dest[0], FALSE);
+ sub_8047B0C(num1, &dest[5], TRUE);
+}
+
+// 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 a)
+{
+ s16 data6 = 0;
+ u8 healthboxLeftSpriteId;
+ u8 healthboxRightSpriteId;
+ u8 healthbarSpriteId;
+ struct Sprite *sprite;
+
+ if (!IsDoubleBattle())
+ {
+ if (GetBattlerSide(a) == B_SIDE_PLAYER)
+ {
+ healthboxLeftSpriteId = CreateSprite(&sHealthboxPlayerSpriteTemplates[0], 240, 160, 1);
+ healthboxRightSpriteId = CreateSpriteAtEnd(&sHealthboxPlayerSpriteTemplates[0], 240, 160, 1);
+
+ gSprites[healthboxLeftSpriteId].oam.shape = SPRITE_SHAPE(64x64);
+ gSprites[healthboxRightSpriteId].oam.shape = SPRITE_SHAPE(64x64);
+ 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].hBar_HealthBoxSpriteId = healthboxLeftSpriteId;
+ gSprites[healthboxRightSpriteId].callback = SpriteCB_HealthBoxOther;
+ }
+ else
+ {
+ if (GetBattlerSide(a) == B_SIDE_PLAYER)
+ {
+ healthboxLeftSpriteId = CreateSprite(&sHealthboxPlayerSpriteTemplates[GetBattlerPosition(a) / 2], 240, 160, 1);
+ healthboxRightSpriteId = CreateSpriteAtEnd(&sHealthboxPlayerSpriteTemplates[GetBattlerPosition(a) / 2], 240, 160, 1);
+
+ gSprites[healthboxLeftSpriteId].oam.affineParam = healthboxRightSpriteId;
+ gSprites[healthboxRightSpriteId].hBar_HealthBoxSpriteId = healthboxLeftSpriteId;
+ gSprites[healthboxRightSpriteId].oam.tileNum += 32;
+ gSprites[healthboxRightSpriteId].callback = SpriteCB_HealthBoxOther;
+ data6 = 1;
+ }
+ else
+ {
+ healthboxLeftSpriteId = CreateSprite(&sHealthboxOpponentSpriteTemplates[GetBattlerPosition(a) / 2], 240, 160, 1);
+ healthboxRightSpriteId = CreateSpriteAtEnd(&sHealthboxOpponentSpriteTemplates[GetBattlerPosition(a) / 2], 240, 160, 1);
+
+ gSprites[healthboxLeftSpriteId].oam.affineParam = healthboxRightSpriteId;
+ gSprites[healthboxRightSpriteId].hBar_HealthBoxSpriteId = healthboxLeftSpriteId;
+ gSprites[healthboxRightSpriteId].oam.tileNum += 32;
+ gSprites[healthboxRightSpriteId].callback = SpriteCB_HealthBoxOther;
+ data6 = 2;
+ }
+ }
+ healthbarSpriteId = CreateSpriteAtEnd(&gUnknown_82602F8[gBattlerPositions[a]], 140, 60, 0);
+ sprite = &gSprites[healthbarSpriteId];
+ SetSubspriteTables(sprite, &gUnknown_82603C4[GetBattlerSide(a)]);
+ sprite->subspriteMode = SUBSPRITES_IGNORE_PRIORITY;
+ sprite->oam.priority = 1;
+ CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_1), OBJ_VRAM0 + sprite->oam.tileNum * 32, 64);
+
+ gSprites[healthboxLeftSpriteId].hBar_HealthBoxSpriteId = healthbarSpriteId;
+ gSprites[healthboxLeftSpriteId].hBar_Data6 = a;
+ gSprites[healthboxLeftSpriteId].invisible = TRUE;
+ gSprites[healthboxRightSpriteId].invisible = TRUE;
+ sprite->data[5] = healthboxLeftSpriteId;
+ sprite->data[6] = data6;
+ sprite->invisible = TRUE;
+
+ return healthboxLeftSpriteId;
+}
+
+u8 CreateSafariPlayerHealthboxSprites(void)
+{
+ u8 healthboxLeftSpriteId = CreateSprite(&sHealthboxSafariSpriteTemplate, 240, 160, 1);
+ u8 healthboxRightSpriteId = CreateSpriteAtEnd(&sHealthboxSafariSpriteTemplate, 240, 160, 1);
+
+ gSprites[healthboxLeftSpriteId].oam.shape = SPRITE_SHAPE(64x64);
+ gSprites[healthboxRightSpriteId].oam.shape = SPRITE_SHAPE(64x64);
+ gSprites[healthboxRightSpriteId].oam.tileNum += 0x40;
+ gSprites[healthboxLeftSpriteId].oam.affineParam = healthboxRightSpriteId;
+ gSprites[healthboxRightSpriteId].hBar_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 r5 = sprite->data[5];
+
+ switch (sprite->data[6])
+ {
+ case 0:
+ sprite->pos1.x = gSprites[r5].pos1.x + 16;
+ sprite->pos1.y = gSprites[r5].pos1.y;
+ break;
+ case 1:
+ sprite->pos1.x = gSprites[r5].pos1.x + 16;
+ sprite->pos1.y = gSprites[r5].pos1.y;
+ break;
+ default:
+ case 2:
+ sprite->pos1.x = gSprites[r5].pos1.x + 8;
+ sprite->pos1.y = gSprites[r5].pos1.y;
+ break;
+ }
+ sprite->pos2.x = gSprites[r5].pos2.x;
+ sprite->pos2.y = gSprites[r5].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 = 75;
+ break;
+ case B_POSITION_PLAYER_RIGHT:
+ x = 171, y = 100;
+ 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] = _("{LV_2}");
+ u32 xPos, var1;
+ void *objVram;
+
+ 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, &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 *strptr;
+ void *objVram;
+
+ if (GetBattlerSide(gSprites[healthboxSpriteId].hMain_Battler) == B_SIDE_PLAYER && !IsDoubleBattle())
+ {
+ u8 text[8];
+ if (maxOrCurrent != HP_CURRENT) // singles, max
+ {
+ ConvertIntToDecimalStringN(text, value, STR_CONV_MODE_RIGHT_ALIGN, 3);
+ windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, 0, 5, &windowId);
+ spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum;
+ TextIntoHealthboxObject( (void*)(OBJ_VRAM0) + spriteTileNum * TILE_SIZE_4BPP + 0xA40, windowTileData, 2);
+ RemoveWindowOnHealthbox(windowId);
+ }
+ else // singles, current
+ {
+ strptr = ConvertIntToDecimalStringN(text, value, STR_CONV_MODE_RIGHT_ALIGN, 3);
+ *strptr++ = CHAR_SLASH;
+ *strptr++ = EOS;
+ windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, 4, 5, &windowId);
+ spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum;
+ TextIntoHealthboxObject((void *)(OBJ_VRAM0) + spriteTileNum * TILE_SIZE_4BPP + 0x2E0, windowTileData, 1);
+ TextIntoHealthboxObject((void *)(OBJ_VRAM0) + spriteTileNum * TILE_SIZE_4BPP + 0xA00, windowTileData + 0x20, 2);
+ RemoveWindowOnHealthbox(windowId);
+ }
+ }
+ else
+ {
+ u8 battler;
+
+ u8 text[20] = __("{COLOR 01}{HIGHLIGHT 02}");
+ battler = gSprites[healthboxSpriteId].hMain_Battler;
+ if (IsDoubleBattle() == TRUE || GetBattlerSide(battler) == B_SIDE_OPPONENT)
+ {
+ UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, value, maxOrCurrent);
+ }
+ else
+ {
+ 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 = 20;
+ else
+ var = 48;
+ }
+
+ ConvertIntToDecimalStringN(text + 6, value, STR_CONV_MODE_RIGHT_ALIGN, 3);
+ RenderTextFont9(gMonSpritesGfxPtr->barFontGfx, 0, text, 0, 0, 0, 0, 0);
+
+ 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 const u8 gUnknown_8260540[] = _("/");
+
+static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent)
+{
+ u32 windowId, spriteTileNum;
+ u8 *windowTileData;
+ void *objVram;
+
+ u8 battlerId;
+
+ u8 text[20] = __("{COLOR 01}{HIGHLIGHT 00}");
+ 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, gUnknown_8260540);
+ RenderTextFont9(gMonSpritesGfxPtr->barFontGfx, 0, text, 0, 0, 0, 0, 0);
+
+ 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] = __("{COLOR 01}{HIGHLIGHT 02}");
+ s32 j, spriteTileNum;
+ u8 *barFontGfx;
+ u8 i, var, nature, healthBarSpriteId;
+
+ barFontGfx = &gMonSpritesGfxPtr->barFontGfx[0x520 + (GetBattlerPosition(gSprites[healthboxSpriteId].hMain_Battler) * 384)];
+ var = 5;
+ nature = GetNature(mon);
+ StringCopy(text + 6, gNatureNamePointers[nature]);
+ RenderTextFont9(barFontGfx, 0, text, 0, 0, 0, 0, 0);
+
+ 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 = HEALTHBOX_GFX_44;
+ else if ((text[j] >= 75 && text[j] <= 79) || (text[j] >= 155 && text[j] <= 159))
+ elementId = HEALTHBOX_GFX_45;
+ else
+ elementId = HEALTHBOX_GFX_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, 0, text, 0, 0, 0, 0, 0);
+
+ 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;
+ }
+ }
+}
+
+#define tBattler data[0]
+#define tSummaryBarSpriteId data[1]
+#define tBallIconSpriteId(n) data[3 + n]
+#define tIsBattleStart data[10]
+#define tData15 data[15]
+
+#ifdef NONMATCHING
+static u8 CreatePartyStatusSummarySprites(u8 battlerId, struct HpAndStatus *partyInfo, u8 arg2, bool8 isBattleStart)
+{
+ bool8 isOpponent;
+ s8 sp14;
+ s16 bar_X, bar_Y, bar_pos2_X, bar_data0;
+ s32 i;
+ 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;
+ }
+
+ for (i = 0, sp14 = 0; i < PARTY_SIZE; i++)
+ {
+ if (partyInfo[i].hp != 0xFFFF)
+ sp14++;
+ }
+
+ LoadCompressedSpriteSheetUsingHeap(&sStatusSummaryBarSpriteSheets[isOpponent]);
+ LoadSpriteSheet(&sStatusSummaryBallsSpriteSheets[isOpponent]);
+ LoadSpritePalette(&sStatusSummaryBarSpritePals[isOpponent]);
+ LoadSpritePalette(&sStatusSummaryBallsSpritePals[isOpponent]);
+
+ 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 = ST_OAM_HFLIP;
+ }
+ 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)
+ {
+ for (i = 0; i < PARTY_SIZE; i++)
+ {
+ if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
+ {
+ 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
+ {
+ if (i >= sp14) // 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
+ {
+ /*
+ * FIXME: r4 and r5 are loaded correctly but in the wrong
+ * order.
+ */
+ for (i = 0; i < PARTY_SIZE; i++)
+ {
+ if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
+ {
+ if (partyInfo[i].hp == 0xFFFF) // empty slot or an egg
+ {
+ gSprites[ballIconSpritesIds[5 - i]].oam.tileNum += 1;
+ gSprites[ballIconSpritesIds[5 - i]].data[7] = 1;
+ }
+ else if (partyInfo[i].hp == 0) // fainted mon
+ {
+ gSprites[ballIconSpritesIds[5 - i]].oam.tileNum += 3;
+ }
+ else if (partyInfo[i].status != 0) // mon with major status
+ {
+ gSprites[ballIconSpritesIds[5 - i]].oam.tileNum += 2;
+ }
+ }
+ else
+ {
+ if (i >= sp14) // empty slot or an egg
+ {
+ gSprites[ballIconSpritesIds[5 - i]].oam.tileNum += 1;
+ gSprites[ballIconSpritesIds[5 - i]].data[7] = 1;
+ }
+ else if (partyInfo[i].hp == 0) // fainted mon
+ {
+ gSprites[ballIconSpritesIds[5 - i]].oam.tileNum += 3;
+ }
+ else if (partyInfo[i].status != 0) // mon with major status
+ {
+ gSprites[ballIconSpritesIds[5 - i]].oam.tileNum += 2;
+ }
+ }
+ }
+ }
+
+ 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;
+ PlaySE12WithPanning(SE_TB_START, 0);
+ return taskId;
+}
+#else
+NAKED
+u8 CreatePartyStatusSummarySprites(u8 battlerId, struct HpAndStatus *partyInfo, u8 arg2, bool8 isBattleStart)
+{
+ asm_unified("\tpush {r4-r7,lr}\n"
+ "\tmov r7, r10\n"
+ "\tmov r6, r9\n"
+ "\tmov r5, r8\n"
+ "\tpush {r5-r7}\n"
+ "\tsub sp, 0x28\n"
+ "\tstr r1, [sp, 0xC]\n"
+ "\tlsls r0, 24\n"
+ "\tlsrs r0, 24\n"
+ "\tstr r0, [sp, 0x8]\n"
+ "\tlsls r2, 24\n"
+ "\tlsrs r2, 24\n"
+ "\tadds r4, r2, 0\n"
+ "\tlsls r3, 24\n"
+ "\tlsrs r3, 24\n"
+ "\tstr r3, [sp, 0x10]\n"
+ "\tcmp r4, 0\n"
+ "\tbeq _08048D44\n"
+ "\tbl GetBattlerPosition\n"
+ "\tlsls r0, 24\n"
+ "\tlsrs r0, 24\n"
+ "\tcmp r0, 0x3\n"
+ "\tbeq _08048D88\n"
+ "_08048D44:\n"
+ "\tldr r0, [sp, 0x8]\n"
+ "\tbl GetBattlerSide\n"
+ "\tlsls r0, 24\n"
+ "\tcmp r0, 0\n"
+ "\tbne _08048D64\n"
+ "\tmovs r7, 0\n"
+ "\tmovs r1, 0x88\n"
+ "\tmovs r2, 0x60\n"
+ "\tmovs r0, 0x64\n"
+ "\tmov r8, r0\n"
+ "\tldr r5, _08048D60 @ =0x0000fffb\n"
+ "\tb _08048D94\n"
+ "\t.align 2, 0\n"
+ "_08048D60: .4byte 0x0000fffb\n"
+ "_08048D64:\n"
+ "\tmovs r7, 0x1\n"
+ "\tcmp r4, 0\n"
+ "\tbeq _08048D74\n"
+ "\tbl IsDoubleBattle\n"
+ "\tlsls r0, 24\n"
+ "\tcmp r0, 0\n"
+ "\tbne _08048D7A\n"
+ "_08048D74:\n"
+ "\tmovs r1, 0x68\n"
+ "\tmovs r2, 0x28\n"
+ "\tb _08048D7E\n"
+ "_08048D7A:\n"
+ "\tmovs r1, 0x68\n"
+ "\tmovs r2, 0x10\n"
+ "_08048D7E:\n"
+ "\tldr r3, _08048D84 @ =0x0000ff9c\n"
+ "\tmov r8, r3\n"
+ "\tb _08048D92\n"
+ "\t.align 2, 0\n"
+ "_08048D84: .4byte 0x0000ff9c\n"
+ "_08048D88:\n"
+ "\tmovs r7, 0x1\n"
+ "\tmovs r1, 0x68\n"
+ "\tmovs r2, 0x28\n"
+ "\tldr r5, _08048E40 @ =0x0000ff9c\n"
+ "\tmov r8, r5\n"
+ "_08048D92:\n"
+ "\tmovs r5, 0x5\n"
+ "_08048D94:\n"
+ "\tmovs r6, 0\n"
+ "\tstr r6, [sp, 0x14]\n"
+ "\tlsls r4, r7, 3\n"
+ "\tldr r0, _08048E44 @ =sStatusSummaryBarSpriteSheets\n"
+ "\tmov r10, r0\n"
+ "\tlsls r3, r7, 1\n"
+ "\tmov r9, r3\n"
+ "\tlsls r1, 16\n"
+ "\tstr r1, [sp, 0x20]\n"
+ "\tlsls r2, 16\n"
+ "\tstr r2, [sp, 0x24]\n"
+ "\tldr r2, _08048E48 @ =0x0000ffff\n"
+ "\tldr r1, [sp, 0xC]\n"
+ "\tmovs r6, 0x5\n"
+ "_08048DB0:\n"
+ "\tldrh r0, [r1]\n"
+ "\tcmp r0, r2\n"
+ "\tbeq _08048DC4\n"
+ "\tldr r3, [sp, 0x14]\n"
+ "\tlsls r0, r3, 24\n"
+ "\tmovs r3, 0x80\n"
+ "\tlsls r3, 17\n"
+ "\tadds r0, r3\n"
+ "\tlsrs r0, 24\n"
+ "\tstr r0, [sp, 0x14]\n"
+ "_08048DC4:\n"
+ "\tadds r1, 0x8\n"
+ "\tsubs r6, 0x1\n"
+ "\tcmp r6, 0\n"
+ "\tbge _08048DB0\n"
+ "\tmov r6, r10\n"
+ "\tadds r0, r4, r6\n"
+ "\tbl LoadCompressedSpriteSheetUsingHeap\n"
+ "\tldr r0, _08048E4C @ =sStatusSummaryBallsSpriteSheets\n"
+ "\tadds r0, r4, r0\n"
+ "\tbl LoadSpriteSheet\n"
+ "\tldr r0, _08048E50 @ =sStatusSummaryBarSpritePals\n"
+ "\tadds r0, r4, r0\n"
+ "\tbl LoadSpritePalette\n"
+ "\tldr r0, _08048E54 @ =sStatusSummaryBallsSpritePals\n"
+ "\tadds r0, r4, r0\n"
+ "\tbl LoadSpritePalette\n"
+ "\tmov r1, r9\n"
+ "\tadds r0, r1, r7\n"
+ "\tlsls r0, 3\n"
+ "\tldr r1, _08048E58 @ =sStatusSummaryBarSpriteTemplates\n"
+ "\tadds r0, r1\n"
+ "\tldr r2, [sp, 0x20]\n"
+ "\tasrs r1, r2, 16\n"
+ "\tldr r3, [sp, 0x24]\n"
+ "\tasrs r2, r3, 16\n"
+ "\tmovs r3, 0xA\n"
+ "\tbl CreateSprite\n"
+ "\tlsls r0, 24\n"
+ "\tlsrs r0, 24\n"
+ "\tstr r0, [sp, 0x18]\n"
+ "\tlsls r0, 4\n"
+ "\tldr r6, [sp, 0x18]\n"
+ "\tadds r0, r6\n"
+ "\tlsls r0, 2\n"
+ "\tldr r1, _08048E5C @ =gSprites\n"
+ "\tadds r4, r0, r1\n"
+ "\tldr r1, _08048E60 @ =sStatusSummaryBar_SubspriteTable\n"
+ "\tadds r0, r4, 0\n"
+ "\tbl SetSubspriteTables\n"
+ "\tmov r0, r8\n"
+ "\tstrh r0, [r4, 0x24]\n"
+ "\tstrh r5, [r4, 0x2E]\n"
+ "\tcmp r7, 0\n"
+ "\tbeq _08048E64\n"
+ "\tldrh r0, [r4, 0x20]\n"
+ "\tsubs r0, 0x60\n"
+ "\tstrh r0, [r4, 0x20]\n"
+ "\tldrb r1, [r4, 0x3]\n"
+ "\tmovs r0, 0x3F\n"
+ "\tnegs r0, r0\n"
+ "\tands r0, r1\n"
+ "\tmovs r1, 0x10\n"
+ "\torrs r0, r1\n"
+ "\tstrb r0, [r4, 0x3]\n"
+ "\tb _08048E6A\n"
+ "\t.align 2, 0\n"
+ "_08048E40: .4byte 0x0000ff9c\n"
+ "_08048E44: .4byte sStatusSummaryBarSpriteSheets\n"
+ "_08048E48: .4byte 0x0000ffff\n"
+ "_08048E4C: .4byte sStatusSummaryBallsSpriteSheets\n"
+ "_08048E50: .4byte sStatusSummaryBarSpritePals\n"
+ "_08048E54: .4byte sStatusSummaryBallsSpritePals\n"
+ "_08048E58: .4byte sStatusSummaryBarSpriteTemplates\n"
+ "_08048E5C: .4byte gSprites\n"
+ "_08048E60: .4byte sStatusSummaryBar_SubspriteTable\n"
+ "_08048E64:\n"
+ "\tldrh r0, [r4, 0x20]\n"
+ "\tadds r0, 0x60\n"
+ "\tstrh r0, [r4, 0x20]\n"
+ "_08048E6A:\n"
+ "\tmovs r6, 0\n"
+ "\tldr r1, _08048F14 @ =gSprites\n"
+ "\tmov r10, r1\n"
+ "\tmov r4, sp\n"
+ "\tmov r2, r9\n"
+ "\tadds r0, r2, r7\n"
+ "\tlsls r0, 3\n"
+ "\tstr r0, [sp, 0x1C]\n"
+ "\tmovs r3, 0xA\n"
+ "\tmov r9, r3\n"
+ "\tmov r8, r6\n"
+ "_08048E80:\n"
+ "\tldr r0, _08048F18 @ =sStatusSummaryBallsSpriteTemplates\n"
+ "\tldr r5, [sp, 0x24]\n"
+ "\tldr r1, _08048F1C @ =0xfffc0000\n"
+ "\tadds r2, r5, r1\n"
+ "\tldr r3, [sp, 0x1C]\n"
+ "\tadds r0, r3, r0\n"
+ "\tldr r5, [sp, 0x20]\n"
+ "\tasrs r1, r5, 16\n"
+ "\tasrs r2, 16\n"
+ "\tmovs r3, 0x9\n"
+ "\tbl CreateSpriteAtEnd\n"
+ "\tstrb r0, [r4]\n"
+ "\tldr r0, [sp, 0x10]\n"
+ "\tcmp r0, 0\n"
+ "\tbne _08048EB0\n"
+ "\tldrb r0, [r4]\n"
+ "\tlsls r1, r0, 4\n"
+ "\tadds r1, r0\n"
+ "\tlsls r1, 2\n"
+ "\tldr r2, _08048F20 @ =gSprites + 0x1C\n"
+ "\tadds r1, r2\n"
+ "\tldr r0, _08048F24 @ =SpriteCB_StatusSummaryBallsOnSwitchout\n"
+ "\tstr r0, [r1]\n"
+ "_08048EB0:\n"
+ "\tldr r5, _08048F14 @ =gSprites\n"
+ "\tcmp r7, 0\n"
+ "\tbne _08048ECE\n"
+ "\tldrb r1, [r4]\n"
+ "\tlsls r0, r1, 4\n"
+ "\tadds r0, r1\n"
+ "\tlsls r0, 2\n"
+ "\tadd r0, r10\n"
+ "\tstrh r7, [r0, 0x24]\n"
+ "\tldrb r1, [r4]\n"
+ "\tlsls r0, r1, 4\n"
+ "\tadds r0, r1\n"
+ "\tlsls r0, 2\n"
+ "\tadd r0, r10\n"
+ "\tstrh r7, [r0, 0x26]\n"
+ "_08048ECE:\n"
+ "\tldrb r1, [r4]\n"
+ "\tlsls r0, r1, 4\n"
+ "\tadds r0, r1\n"
+ "\tlsls r0, 2\n"
+ "\tadds r0, r5\n"
+ "\tmovs r1, 0\n"
+ "\tmov r3, sp\n"
+ "\tldrh r3, [r3, 0x18]\n"
+ "\tstrh r3, [r0, 0x2E]\n"
+ "\tcmp r7, 0\n"
+ "\tbne _08048F28\n"
+ "\tldrb r0, [r4]\n"
+ "\tlsls r1, r0, 4\n"
+ "\tadds r1, r0\n"
+ "\tlsls r1, 2\n"
+ "\tadds r1, r5\n"
+ "\tldrh r0, [r1, 0x20]\n"
+ "\tadds r0, 0x18\n"
+ "\tadd r0, r8\n"
+ "\tstrh r0, [r1, 0x20]\n"
+ "\tldrb r1, [r4]\n"
+ "\tlsls r0, r1, 4\n"
+ "\tadds r0, r1\n"
+ "\tlsls r0, 2\n"
+ "\tadds r0, r5\n"
+ "\tmov r1, r9\n"
+ "\tstrh r1, [r0, 0x30]\n"
+ "\tldrb r1, [r4]\n"
+ "\tlsls r0, r1, 4\n"
+ "\tadds r0, r1\n"
+ "\tlsls r0, 2\n"
+ "\tadds r0, r5\n"
+ "\tmovs r1, 0x78\n"
+ "\tb _08048F66\n"
+ "\t.align 2, 0\n"
+ "_08048F14: .4byte gSprites\n"
+ "_08048F18: .4byte sStatusSummaryBallsSpriteTemplates\n"
+ "_08048F1C: .4byte 0xfffc0000\n"
+ "_08048F20: .4byte gSprites + 0x1C\n"
+ "_08048F24: .4byte SpriteCB_StatusSummaryBallsOnSwitchout\n"
+ "_08048F28:\n"
+ "\tldrb r0, [r4]\n"
+ "\tlsls r2, r0, 4\n"
+ "\tadds r2, r0\n"
+ "\tlsls r2, 2\n"
+ "\tadds r2, r5\n"
+ "\tldrh r3, [r2, 0x20]\n"
+ "\tsubs r3, 0x18\n"
+ "\tmovs r1, 0x5\n"
+ "\tsubs r1, r6\n"
+ "\tlsls r0, r1, 2\n"
+ "\tadds r0, r1\n"
+ "\tlsls r0, 1\n"
+ "\tsubs r3, r0\n"
+ "\tstrh r3, [r2, 0x20]\n"
+ "\tldrb r0, [r4]\n"
+ "\tlsls r2, r0, 4\n"
+ "\tadds r2, r0\n"
+ "\tlsls r2, 2\n"
+ "\tadds r2, r5\n"
+ "\tmovs r1, 0x6\n"
+ "\tsubs r1, r6\n"
+ "\tlsls r0, r1, 3\n"
+ "\tsubs r0, r1\n"
+ "\tadds r0, 0xA\n"
+ "\tstrh r0, [r2, 0x30]\n"
+ "\tldrb r1, [r4]\n"
+ "\tlsls r0, r1, 4\n"
+ "\tadds r0, r1\n"
+ "\tlsls r0, 2\n"
+ "\tadds r0, r5\n"
+ "\tldr r1, _08048FD4 @ =0x0000ff88\n"
+ "_08048F66:\n"
+ "\tstrh r1, [r0, 0x24]\n"
+ "\tldrb r1, [r4]\n"
+ "\tlsls r0, r1, 4\n"
+ "\tadds r0, r1\n"
+ "\tlsls r0, 2\n"
+ "\tadds r0, r5\n"
+ "\tstrh r7, [r0, 0x32]\n"
+ "\tadds r4, 0x1\n"
+ "\tmovs r2, 0x7\n"
+ "\tadd r9, r2\n"
+ "\tmovs r3, 0xA\n"
+ "\tadd r8, r3\n"
+ "\tadds r6, 0x1\n"
+ "\tcmp r6, 0x5\n"
+ "\tbgt _08048F86\n"
+ "\tb _08048E80\n"
+ "_08048F86:\n"
+ "\tldr r0, [sp, 0x8]\n"
+ "\tbl GetBattlerSide\n"
+ "\tlsls r0, 24\n"
+ "\tcmp r0, 0\n"
+ "\tbne _0804906E\n"
+ "\tmovs r6, 0\n"
+ "\tldr r5, _08048FD8 @ =gBattleTypeFlags\n"
+ "\tmov r10, r5\n"
+ "\tldr r0, _08048FDC @ =0x0000ffff\n"
+ "\tmov r9, r0\n"
+ "\tldr r7, _08048FE0 @ =gSprites\n"
+ "\tldr r1, _08048FE4 @ =0x000003ff\n"
+ "\tmov r12, r1\n"
+ "\tldr r2, _08048FE8 @ =0xfffffc00\n"
+ "\tmov r8, r2\n"
+ "\tmov r4, sp\n"
+ "\tldr r5, [sp, 0xC]\n"
+ "_08048FAA:\n"
+ "\tmov r3, r10\n"
+ "\tldr r0, [r3]\n"
+ "\tmovs r1, 0x40\n"
+ "\tands r0, r1\n"
+ "\tcmp r0, 0\n"
+ "\tbeq _08048FEC\n"
+ "\tldrh r0, [r5]\n"
+ "\tcmp r0, r9\n"
+ "\tbeq _08048FF6\n"
+ "\tcmp r0, 0\n"
+ "\tbne _0804903E\n"
+ "\tldrb r0, [r4]\n"
+ "\tlsls r2, r0, 4\n"
+ "\tadds r2, r0\n"
+ "\tlsls r2, 2\n"
+ "\tadds r2, r7\n"
+ "\tldrh r3, [r2, 0x4]\n"
+ "\tlsls r1, r3, 22\n"
+ "\tlsrs r1, 22\n"
+ "\tadds r1, 0x3\n"
+ "\tb _08049056\n"
+ "\t.align 2, 0\n"
+ "_08048FD4: .4byte 0x0000ff88\n"
+ "_08048FD8: .4byte gBattleTypeFlags\n"
+ "_08048FDC: .4byte 0x0000ffff\n"
+ "_08048FE0: .4byte gSprites\n"
+ "_08048FE4: .4byte 0x000003ff\n"
+ "_08048FE8: .4byte 0xfffffc00\n"
+ "_08048FEC:\n"
+ "\tldr r1, [sp, 0x14]\n"
+ "\tlsls r0, r1, 24\n"
+ "\tasrs r0, 24\n"
+ "\tcmp r6, r0\n"
+ "\tblt _08049024\n"
+ "_08048FF6:\n"
+ "\tldrb r0, [r4]\n"
+ "\tlsls r2, r0, 4\n"
+ "\tadds r2, r0\n"
+ "\tlsls r2, 2\n"
+ "\tadds r2, r7\n"
+ "\tldrh r3, [r2, 0x4]\n"
+ "\tlsls r1, r3, 22\n"
+ "\tlsrs r1, 22\n"
+ "\tadds r1, 0x1\n"
+ "\tmov r0, r12\n"
+ "\tands r1, r0\n"
+ "\tmov r0, r8\n"
+ "\tands r0, r3\n"
+ "\torrs r0, r1\n"
+ "\tstrh r0, [r2, 0x4]\n"
+ "\tldrb r1, [r4]\n"
+ "\tlsls r0, r1, 4\n"
+ "\tadds r0, r1\n"
+ "\tlsls r0, 2\n"
+ "\tadds r0, r7\n"
+ "\tmovs r1, 0x1\n"
+ "\tstrh r1, [r0, 0x3C]\n"
+ "\tb _08049062\n"
+ "_08049024:\n"
+ "\tldrh r0, [r5]\n"
+ "\tcmp r0, 0\n"
+ "\tbne _0804903E\n"
+ "\tldrb r0, [r4]\n"
+ "\tlsls r2, r0, 4\n"
+ "\tadds r2, r0\n"
+ "\tlsls r2, 2\n"
+ "\tadds r2, r7\n"
+ "\tldrh r3, [r2, 0x4]\n"
+ "\tlsls r1, r3, 22\n"
+ "\tlsrs r1, 22\n"
+ "\tadds r1, 0x3\n"
+ "\tb _08049056\n"
+ "_0804903E:\n"
+ "\tldr r0, [r5, 0x4]\n"
+ "\tcmp r0, 0\n"
+ "\tbeq _08049062\n"
+ "\tldrb r0, [r4]\n"
+ "\tlsls r2, r0, 4\n"
+ "\tadds r2, r0\n"
+ "\tlsls r2, 2\n"
+ "\tadds r2, r7\n"
+ "\tldrh r3, [r2, 0x4]\n"
+ "\tlsls r1, r3, 22\n"
+ "\tlsrs r1, 22\n"
+ "\tadds r1, 0x2\n"
+ "_08049056:\n"
+ "\tmov r0, r12\n"
+ "\tands r1, r0\n"
+ "\tmov r0, r8\n"
+ "\tands r0, r3\n"
+ "\torrs r0, r1\n"
+ "\tstrh r0, [r2, 0x4]\n"
+ "_08049062:\n"
+ "\tadds r4, 0x1\n"
+ "\tadds r5, 0x8\n"
+ "\tadds r6, 0x1\n"
+ "\tcmp r6, 0x5\n"
+ "\tble _08048FAA\n"
+ "\tb _08049148\n"
+ "_0804906E:\n"
+ "\tmovs r6, 0\n"
+ "\tldr r1, _080490B4 @ =gBattleTypeFlags\n"
+ "\tmov r10, r1\n"
+ "\tldr r2, _080490B8 @ =0x0000ffff\n"
+ "\tmov r9, r2\n"
+ "\tldr r7, _080490BC @ =gSprites\n"
+ "\tldr r3, _080490C0 @ =0x000003ff\n"
+ "\tmov r12, r3\n"
+ "\tldr r5, _080490C4 @ =0xfffffc00\n"
+ "\tmov r8, r5\n"
+ "\tldr r5, [sp, 0xC]\n"
+ "\tmov r4, sp\n"
+ "\tadds r4, 0x5\n"
+ "_08049088:\n"
+ "\tmov r1, r10\n"
+ "\tldr r0, [r1]\n"
+ "\tmovs r1, 0x40\n"
+ "\tands r0, r1\n"
+ "\tcmp r0, 0\n"
+ "\tbeq _080490C8\n"
+ "\tldrh r0, [r5]\n"
+ "\tcmp r0, r9\n"
+ "\tbeq _080490D2\n"
+ "\tcmp r0, 0\n"
+ "\tbne _0804911A\n"
+ "\tldrb r0, [r4]\n"
+ "\tlsls r2, r0, 4\n"
+ "\tadds r2, r0\n"
+ "\tlsls r2, 2\n"
+ "\tadds r2, r7\n"
+ "\tldrh r3, [r2, 0x4]\n"
+ "\tlsls r1, r3, 22\n"
+ "\tlsrs r1, 22\n"
+ "\tadds r1, 0x3\n"
+ "\tb _08049132\n"
+ "\t.align 2, 0\n"
+ "_080490B4: .4byte gBattleTypeFlags\n"
+ "_080490B8: .4byte 0x0000ffff\n"
+ "_080490BC: .4byte gSprites\n"
+ "_080490C0: .4byte 0x000003ff\n"
+ "_080490C4: .4byte 0xfffffc00\n"
+ "_080490C8:\n"
+ "\tldr r1, [sp, 0x14]\n"
+ "\tlsls r0, r1, 24\n"
+ "\tasrs r0, 24\n"
+ "\tcmp r6, r0\n"
+ "\tblt _08049100\n"
+ "_080490D2:\n"
+ "\tldrb r0, [r4]\n"
+ "\tlsls r2, r0, 4\n"
+ "\tadds r2, r0\n"
+ "\tlsls r2, 2\n"
+ "\tadds r2, r7\n"
+ "\tldrh r3, [r2, 0x4]\n"
+ "\tlsls r1, r3, 22\n"
+ "\tlsrs r1, 22\n"
+ "\tadds r1, 0x1\n"
+ "\tmov r0, r12\n"
+ "\tands r1, r0\n"
+ "\tmov r0, r8\n"
+ "\tands r0, r3\n"
+ "\torrs r0, r1\n"
+ "\tstrh r0, [r2, 0x4]\n"
+ "\tldrb r1, [r4]\n"
+ "\tlsls r0, r1, 4\n"
+ "\tadds r0, r1\n"
+ "\tlsls r0, 2\n"
+ "\tadds r0, r7\n"
+ "\tmovs r1, 0x1\n"
+ "\tstrh r1, [r0, 0x3C]\n"
+ "\tb _0804913E\n"
+ "_08049100:\n"
+ "\tldrh r0, [r5]\n"
+ "\tcmp r0, 0\n"
+ "\tbne _0804911A\n"
+ "\tldrb r0, [r4]\n"
+ "\tlsls r2, r0, 4\n"
+ "\tadds r2, r0\n"
+ "\tlsls r2, 2\n"
+ "\tadds r2, r7\n"
+ "\tldrh r3, [r2, 0x4]\n"
+ "\tlsls r1, r3, 22\n"
+ "\tlsrs r1, 22\n"
+ "\tadds r1, 0x3\n"
+ "\tb _08049132\n"
+ "_0804911A:\n"
+ "\tldr r0, [r5, 0x4]\n"
+ "\tcmp r0, 0\n"
+ "\tbeq _0804913E\n"
+ "\tldrb r0, [r4]\n"
+ "\tlsls r2, r0, 4\n"
+ "\tadds r2, r0\n"
+ "\tlsls r2, 2\n"
+ "\tadds r2, r7\n"
+ "\tldrh r3, [r2, 0x4]\n"
+ "\tlsls r1, r3, 22\n"
+ "\tlsrs r1, 22\n"
+ "\tadds r1, 0x2\n"
+ "_08049132:\n"
+ "\tmov r0, r12\n"
+ "\tands r1, r0\n"
+ "\tmov r0, r8\n"
+ "\tands r0, r3\n"
+ "\torrs r0, r1\n"
+ "\tstrh r0, [r2, 0x4]\n"
+ "_0804913E:\n"
+ "\tsubs r4, 0x1\n"
+ "\tadds r5, 0x8\n"
+ "\tadds r6, 0x1\n"
+ "\tcmp r6, 0x5\n"
+ "\tble _08049088\n"
+ "_08049148:\n"
+ "\tldr r0, _080491A8 @ =TaskDummy\n"
+ "\tmovs r1, 0x5\n"
+ "\tbl CreateTask\n"
+ "\tlsls r0, 24\n"
+ "\tlsrs r4, r0, 24\n"
+ "\tldr r2, _080491AC @ =gTasks\n"
+ "\tlsls r3, r4, 2\n"
+ "\tadds r1, r3, r4\n"
+ "\tlsls r1, 3\n"
+ "\tadds r0, r1, r2\n"
+ "\tmov r5, sp\n"
+ "\tldrh r5, [r5, 0x8]\n"
+ "\tstrh r5, [r0, 0x8]\n"
+ "\tmov r6, sp\n"
+ "\tldrh r6, [r6, 0x18]\n"
+ "\tstrh r6, [r0, 0xA]\n"
+ "\tmovs r6, 0\n"
+ "\tadds r0, r2, 0\n"
+ "\tadds r0, 0xE\n"
+ "\tadds r1, r0\n"
+ "_08049172:\n"
+ "\tmov r5, sp\n"
+ "\tadds r0, r5, r6\n"
+ "\tldrb r0, [r0]\n"
+ "\tstrh r0, [r1]\n"
+ "\tadds r1, 0x2\n"
+ "\tadds r6, 0x1\n"
+ "\tcmp r6, 0x5\n"
+ "\tble _08049172\n"
+ "\tadds r0, r3, r4\n"
+ "\tlsls r0, 3\n"
+ "\tadds r0, r2\n"
+ "\tldrh r6, [r5, 0x10]\n"
+ "\tstrh r6, [r0, 0x1C]\n"
+ "\tmovs r0, 0x6B\n"
+ "\tmovs r1, 0\n"
+ "\tbl PlaySE12WithPanning\n"
+ "\tadds r0, r4, 0\n"
+ "\tadd sp, 0x28\n"
+ "\tpop {r3-r5}\n"
+ "\tmov r8, r3\n"
+ "\tmov r9, r4\n"
+ "\tmov r10, r5\n"
+ "\tpop {r4-r7}\n"
+ "\tpop {r1}\n"
+ "\tbx r1\n"
+ "\t.align 2, 0\n"
+ "_080491A8: .4byte TaskDummy\n"
+ "_080491AC: .4byte gTasks");
+}
+#endif //NONMATCHING
+
+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 = ST_OAM_OBJ_BLEND;
+
+ gSprites[summaryBarSpriteId].oam.objMode = ST_OAM_OBJ_BLEND;
+
+ 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_8049630;
+ }
+ 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_8049630;
+ }
+ }
+ gSprites[summaryBarSpriteId].data[0] /= 2;
+ gSprites[summaryBarSpriteId].data[1] = 0;
+ gSprites[summaryBarSpriteId].callback = sub_8049568;
+ SetSubspriteTables(&gSprites[summaryBarSpriteId], gUnknown_8260404);
+ gTasks[taskId].func = sub_8049388;
+ }
+ else
+ {
+ gTasks[taskId].func = sub_804948C;
+ }
+}
+
+static void sub_8049388(u8 taskId)
+{
+ if ((gTasks[taskId].data[11]++ % 2) == 0)
+ {
+ if (--gTasks[taskId].tData15 < 0)
+ return;
+
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[15], 16 - gTasks[taskId].data[15]));
+ }
+ if (gTasks[taskId].tData15 == 0)
+ gTasks[taskId].func = sub_80493E4;
+}
+
+static void sub_80493E4(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);
+
+ DestroySpriteAndFreeResources(&gSprites[summaryBarSpriteId]);
+ DestroySpriteAndFreeResources(&gSprites[ballIconSpriteIds[0]]);
+
+ for (i = 1; i < PARTY_SIZE; i++)
+ DestroySprite(&gSprites[ballIconSpriteIds[i]]);
+ }
+ else if (gTasks[taskId].tData15 == -3)
+ {
+ SetGpuReg(REG_OFFSET_BLDCNT, 0);
+ SetGpuReg(REG_OFFSET_BLDALPHA, 0);
+ DestroyTask(taskId);
+ }
+}
+
+static void sub_804948C(u8 taskId)
+{
+ u8 ballIconSpriteIds[PARTY_SIZE];
+ s32 i;
+ u8 battlerId = gTasks[taskId].tBattler;
+
+ if (--gTasks[taskId].tData15 >= 0)
+ {
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[15], 16 - gTasks[taskId].data[15]));
+ }
+ 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)
+ {
+ 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_8049568(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_8049630(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 const u8 gUnknown_8260556[] = _("{HIGHLIGHT 02}");
+
+void UpdateNickInHealthbox(u8 healthboxSpriteId, struct Pokemon *mon)
+{
+ u8 nickname[POKEMON_NAME_LENGTH + 1];
+ u8 *ptr;
+ u32 windowId, spriteTileNum;
+ u8 *windowTileData;
+ u16 species;
+ u8 gender;
+
+ ptr = StringCopy(gDisplayedStringBattle, gUnknown_8260556);
+ GetMonData(mon, MON_DATA_NICKNAME, nickname);
+ StringGetEnd10(nickname);
+ ptr = StringCopy(ptr, nickname);
+ *ptr++ = EXT_CTRL_CODE_BEGIN;
+ *ptr++ = EXT_CTRL_CODE_COLOR;
+
+ 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;
+
+ if (CheckBattleTypeGhost(mon, gSprites[healthboxSpriteId].hMain_Battler))
+ 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:
+ *ptr++ = TEXT_DYNAMIC_COLOR_2;
+ *ptr++ = EOS;
+ windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gDisplayedStringBattle, 0, 3, &windowId);
+ break;
+ case MON_MALE:
+ *ptr++ = TEXT_DYNAMIC_COLOR_2;
+ *ptr++ = CHAR_MALE;
+ *ptr++ = EOS;
+ windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gDisplayedStringBattle, 0, 3, &windowId);
+ break;
+ case MON_FEMALE:
+ *ptr++ = TEXT_DYNAMIC_COLOR_1;
+ *ptr++ = CHAR_FEMALE;
+ *ptr++ = EOS;
+ windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gDisplayedStringBattle, 0, 3, &windowId);
+ break;
+ }
+
+ spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum * TILE_SIZE_4BPP;
+
+ if (GetBattlerSide(gSprites[healthboxSpriteId].data[6]) == B_SIDE_PLAYER)
+ {
+ TextIntoHealthboxObject((void*)(OBJ_VRAM0 + 0x40 + spriteTileNum), windowTileData, 6);
+ ptr = (void*)(OBJ_VRAM0);
+ if (!IsDoubleBattle())
+ ptr += spriteTileNum + 0x800;
+ else
+ ptr += spriteTileNum + 0x400;
+ TextIntoHealthboxObject(ptr, windowTileData + 0xC0, 1);
+ }
+ else
+ {
+ TextIntoHealthboxObject((void*)(OBJ_VRAM0 + 0x20 + spriteTileNum), windowTileData, 7);
+ }
+
+ RemoveWindowOnHealthbox(windowId);
+}
+void TryAddPokeballIconToHealthbox(u8 healthboxSpriteId, bool8 noStatus)
+{
+ u8 battlerId, healthBarSpriteId;
+
+ if (gBattleTypeFlags & (BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_OLD_MAN_TUTORIAL | BATTLE_TYPE_POKEDUDE))
+ return;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
+ return;
+
+ battlerId = gSprites[healthboxSpriteId].hMain_Battler;
+ if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
+ return;
+ if (CheckBattleTypeGhost(&gEnemyParty[gBattlerPartyIndexes[battlerId]], battlerId))
+ 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);
+}
+
+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 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, &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_HighlightRed_Left);
+ ConvertIntToDecimalStringN(txtPtr, gNumSafariBalls, STR_CONV_MODE_LEFT_ALIGN, 2);
+
+ windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, GetStringRightAlignXOffset(0, text, 0x2F), 3, &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 (elementId == HEALTHBOX_ALL && !IsDoubleBattle())
+ GetBattlerSide(battlerId); // Pointless function call.
+
+ 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 (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 functions seem as if they were made for testing the health bar.
+static s16 sub_804A460(struct TestingBar *barInfo, s32 *currValue, u8 bg, u8 x, u8 y)
+{
+ s16 ret;
+
+ ret = CalcNewBarValue(barInfo->maxValue,
+ barInfo->oldValue,
+ barInfo->receivedValue,
+ currValue, B_HEALTHBAR_PIXELS / 8, 1);
+
+ sub_804A510(barInfo, currValue, bg, x, y);
+
+ return ret;
+}
+
+static s16 sub_804A4C8(struct TestingBar *barInfo, s32 *currValue)
+{
+ s16 ret;
+
+ ret = CalcNewBarValue(barInfo->maxValue,
+ barInfo->oldValue,
+ barInfo->receivedValue,
+ currValue, B_HEALTHBAR_PIXELS / 8, 1);
+
+ return ret;
+}
+
+static void sub_804A4F0(struct TestingBar *barInfo, s32 *currValue, u8 bg, u8 x, u8 y)
+{
+ sub_804A510(barInfo, currValue, bg, x, y);
+}
+
+static void sub_804A510(struct TestingBar *barInfo, s32 *currValue, u8 bg, u8 x, u8 y)
+{
+ u8 spC[B_HEALTHBAR_PIXELS / 8];
+ u16 tiles[B_HEALTHBAR_PIXELS / 8];
+ u8 i;
+
+ CalcBarFilledPixels(barInfo->maxValue,
+ barInfo->oldValue,
+ barInfo->receivedValue,
+ currValue, spC, B_HEALTHBAR_PIXELS / 8);
+
+ for (i = 0; i < B_HEALTHBAR_PIXELS / 8; i++)
+ {
+ tiles[i] = (barInfo->pal << 12) | (barInfo->tileOffset + spC[i]);
+ }
+
+ CopyToBgTilemapBufferRect_ChangePalette(bg, tiles, x, y, 6, 1, 17);
+}
+
+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 const struct WindowTemplate sHealthboxWindowTemplate = {
+ .bg = 0,
+ .tilemapLeft = 0,
+ .tilemapTop = 0,
+ .width = 8,
+ .height = 2,
+ .paletteNum = 0,
+ .baseBlock = 0x000
+};
+
+
+static u8* AddTextPrinterAndCreateWindowOnHealthbox(const u8 *str, u32 x, u32 y, u32 *windowId)
+{
+ u16 winId;
+ u8 color[3];
+ struct WindowTemplate winTemplate = sHealthboxWindowTemplate;
+
+ winId = AddWindow(&winTemplate);
+ FillWindowPixelBuffer(winId, PIXEL_FILL(2));
+
+ color[0] = 2;
+ 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 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);
+}