diff options
author | PikalaxALT <PikalaxALT@users.noreply.github.com> | 2020-01-12 14:54:43 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-12 14:54:43 -0500 |
commit | 15ff7eb2f87032797f6ce9ef9bb471c468b48a36 (patch) | |
tree | 60d1318e686a7e4c9621ee7697c890b3c21cd696 /src/battle_interface.c | |
parent | 74fa8075ee4018ba9b7e610212cf7c7777c4edb4 (diff) | |
parent | 483613e128d8dc5b419ea9ff83c92aa2e4e55042 (diff) |
Merge pull request #213 from PikalaxALT/script_pokemon_util
script_pokemon_util_80A0058, battle_interface
Diffstat (limited to 'src/battle_interface.c')
-rw-r--r-- | src/battle_interface.c | 2800 |
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); +} |