diff options
author | PikalaxALT <PikalaxALT@gmail.com> | 2020-01-12 12:13:03 -0500 |
---|---|---|
committer | PikalaxALT <PikalaxALT@gmail.com> | 2020-01-12 12:13:03 -0500 |
commit | ae41a2742ced950f37cbe1b21cdf394483ebd05b (patch) | |
tree | a91a0fb1b14cdf466d56cbc941f3ce94a018df03 /src/battle_interface.c | |
parent | d09a3d7f1c6efc990b44b5ea240b36147d94104a (diff) |
Finish battle_interface.c decomp
Diffstat (limited to 'src/battle_interface.c')
-rw-r--r-- | src/battle_interface.c | 807 |
1 files changed, 793 insertions, 14 deletions
diff --git a/src/battle_interface.c b/src/battle_interface.c index 489378a13..4098025fe 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -5,8 +5,11 @@ #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" @@ -14,6 +17,148 @@ #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 +}; + void SpriteCB_HealthBoxOther(struct Sprite * sprite); void SpriteCB_HealthBar(struct Sprite * sprite); const u8 *GetHealthboxElementGfxPtr(u8 which); @@ -27,6 +172,13 @@ void SpriteCB_StatusSummaryBallsOnSwitchout(struct Sprite * sprite); void UpdateStatusIconInHealthbox(u8 spriteId); void SpriteCB_StatusSummaryBar(struct Sprite * sprite); void SpriteCB_StatusSummaryBallsOnBattleStart(struct Sprite * sprite); +u8 GetStatusIconForBattlerId(u8 statusElementId, u8 battlerId); +void MoveBattleBarGraphically(u8 battlerId, u8 whichBar); +u8 GetScaledExpFraction(s32 oldValue, s32 receivedValue, s32 maxValue, u8 scale); +u8 CalcBarFilledPixels(s32 maxValue, s32 oldValue, s32 receivedValue, s32 *currValue, u8 *arg4, u8 scale); +s32 CalcNewBarValue(s32 maxValue, s32 currValue, s32 receivedValue, s32 *arg3, u8 arg4, u16 arg5); +void sub_804A510(struct TestingBar *barInfo, s32 *currValue, u8 bg, u8 x, u8 y); +void SafariTextIntoHealthboxObject(void *dest, u8 *windowTileData, u32 windowWidth); u8 *AddTextPrinterAndCreateWindowOnHealthbox(const u8 *str, u32 x, u32 y, u32 *windowId); void RemoveWindowOnHealthbox(u32 windowId); void TextIntoHealthboxObject(void *dest, u8 *windowTileData, s32 windowWidth); @@ -426,7 +578,7 @@ u8 CreateBattlerHealthboxSprites(u8 a) SetSubspriteTables(sprite, &gUnknown_82603C4[GetBattlerSide(a)]); sprite->subspriteMode = 2; sprite->oam.priority = 1; - CpuCopy32(GetHealthboxElementGfxPtr(1), OBJ_VRAM0 + sprite->oam.tileNum * 32, 64); + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_1), OBJ_VRAM0 + sprite->oam.tileNum * 32, 64); gSprites[healthboxLeftSpriteId].hBar_HealthBoxSpriteId = healthbarSpriteId; gSprites[healthboxLeftSpriteId].hBar_Data6 = a; @@ -753,7 +905,7 @@ void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrC { if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) // Impossible to reach part, because the battlerId is from the opponent's side. { - CpuCopy32(GetHealthboxElementGfxPtr(116), + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_116), (void*)(OBJ_VRAM0) + ((gSprites[healthboxSpriteId].oam.tileNum + 52) * TILE_SIZE_4BPP), 0x20); } @@ -781,11 +933,11 @@ void PrintSafariMonInfo(u8 healthboxSpriteId, struct Pokemon *mon) u8 elementId; if ((text[j] >= 55 && text[j] <= 74) || (text[j] >= 135 && text[j] <= 154)) - elementId = 44; + elementId = HEALTHBOX_GFX_44; else if ((text[j] >= 75 && text[j] <= 79) || (text[j] >= 155 && text[j] <= 159)) - elementId = 45; + elementId = HEALTHBOX_GFX_45; else - elementId = 43; + elementId = HEALTHBOX_GFX_43; CpuCopy32(GetHealthboxElementGfxPtr(elementId), barFontGfx + (i * 64), 0x20); } @@ -860,7 +1012,7 @@ void SwapHpBarsWithHpText(void) { UpdateStatusIconInHealthbox(gHealthboxSpriteIds[i]); UpdateHealthboxAttribute(gHealthboxSpriteIds[i], &gPlayerParty[gBattlerPartyIndexes[i]], HEALTHBOX_HEALTH_BAR); - CpuCopy32(GetHealthboxElementGfxPtr(117), (void*)(OBJ_VRAM0 + 0x680 + gSprites[gHealthboxSpriteIds[i]].oam.tileNum * TILE_SIZE_4BPP), 32); + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_117), (void*)(OBJ_VRAM0 + 0x680 + gSprites[gHealthboxSpriteIds[i]].oam.tileNum * TILE_SIZE_4BPP), 32); } } else @@ -2000,20 +2152,601 @@ void TryAddPokeballIconToHealthbox(u8 healthboxSpriteId, bool8 noStatus) healthBarSpriteId = gSprites[healthboxSpriteId].hMain_HealthBarSpriteId; if (noStatus) - CpuCopy32(GetHealthboxElementGfxPtr(70), (void*)(OBJ_VRAM0 + (gSprites[healthBarSpriteId].oam.tileNum + 8) * TILE_SIZE_4BPP), 32); + 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); } -const u16 gUnknown_826055A[] = { - RGB(24, 12, 24), - RGB(23, 23, 3), - RGB(20, 20, 17), - RGB(17, 22, 28), - RGB(28, 14, 10) +enum +{ + PAL_STATUS_PSN, + PAL_STATUS_PAR, + PAL_STATUS_SLP, + PAL_STATUS_FRZ, + PAL_STATUS_BRN +}; + +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) }; -const struct WindowTemplate gUnknown_8260564 = { +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); +} + +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; +} + +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); +} + +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; +} + +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; + } +} +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; +} + +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. +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; +} + +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; +} + +void sub_804A4F0(struct TestingBar *barInfo, s32 *currValue, u8 bg, u8 x, u8 y) +{ + sub_804A510(barInfo, currValue, bg, x, y); +} + +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); +} + +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; +} + +const struct WindowTemplate sHealthboxWindowTemplate = { .bg = 0, .tilemapLeft = 0, .tilemapTop = 0, @@ -2022,3 +2755,49 @@ const struct WindowTemplate gUnknown_8260564 = { .paletteNum = 0, .baseBlock = 0x000 }; + + +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)); +} + +void RemoveWindowOnHealthbox(u32 windowId) +{ + RemoveWindow(windowId); +} + +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); + } +} + +void SafariTextIntoHealthboxObject(void *dest, u8 *windowTileData, u32 windowWidth) +{ + CpuCopy32(windowTileData, dest, windowWidth * TILE_SIZE_4BPP); + CpuCopy32(windowTileData + 256, dest + 256, windowWidth * TILE_SIZE_4BPP); +} |