diff --git a/engine/battle/core.asm b/engine/battle/core.asm index c0d73bac22..f36e63b10a 100644 --- a/engine/battle/core.asm +++ b/engine/battle/core.asm @@ -1823,6 +1823,7 @@ DrawPlayerHUDAndHPBar: hlcoord 10, 7 call CenterMonName call PlaceString + callfar PrintEXPBar ld hl, wBattleMonSpecies ld de, wLoadedMon ld bc, wBattleMonDVs - wBattleMonSpecies diff --git a/engine/battle/experience.asm b/engine/battle/experience.asm index a8ee6747cb..dc301efdc0 100644 --- a/engine/battle/experience.asm +++ b/engine/battle/experience.asm @@ -151,6 +151,7 @@ GainExperience: xor a ; PLAYER_PARTY_DATA ld [wMonDataLocation], a call LoadMonData + call AnimateEXPBar pop hl ld bc, wPartyMon1Level - wPartyMon1Exp add hl, bc @@ -160,6 +161,7 @@ GainExperience: ld a, [hl] ; current level cp d jp z, .nextMon ; if level didn't change, go to next mon + call KeepEXPBarFull ld a, [wCurEnemyLevel] push af push hl @@ -245,6 +247,7 @@ GainExperience: xor a ; PLAYER_PARTY_DATA ld [wMonDataLocation], a call LoadMonData + call AnimateEXPBarAgain ld d, $1 callfar PrintStatsBox call WaitForTextScrollButtonPress diff --git a/engine/gfx/exp_bar.asm b/engine/gfx/exp_bar.asm new file mode 100644 index 0000000000..cba4fc0676 --- /dev/null +++ b/engine/gfx/exp_bar.asm @@ -0,0 +1,247 @@ +DEF EXP_BAR_BASE_TILE_ID EQU $c0 + +PrintEXPBar: + call CalcEXPBarPixelLength + ldh a, [hQuotient + 3] ; pixel length + ld [wEXPBarPixelLength], a + ld b, a + ld c, 8 + ld d, 8 + hlcoord 17, 11 +.loop + ld a, b + sub c + jr nc, .skip + ld c, b + jr .loop +.skip + ld b, a + ld a, EXP_BAR_BASE_TILE_ID + add c +.loop2 + ld [hld], a + dec d + ret z + ld a, b + and a + jr nz, .loop + ld a, EXP_BAR_BASE_TILE_ID + jr .loop2 + +CalcEXPBarPixelLength: + ld hl, wEXPBarKeepFullFlag + bit 0, [hl] + jr z, .start + res 0, [hl] + ld a, 8 * 8 + ldh [hQuotient + 3], a + ret + +.start + ; get the base exp needed for the current level + ld a, [wPlayerBattleStatus3] + ld hl, wBattleMonSpecies + bit TRANSFORMED, a + jr z, .skip + ld hl, wPartyMon1 + call BattleMonPartyAttr +.skip + ld a, [hl] + ld [wCurSpecies], a + call GetMonHeader + ld a, [wBattleMonLevel] + ld d, a + callfar CalcExperience + ld hl, hMultiplicand + ld de, wEXPBarBaseEXP + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + + ; get the exp needed to gain a level + ld a, [wBattleMonLevel] + ld d, a + inc d + callfar CalcExperience + + ; get the address of the active Pokemon's current experience + ld hl, wPartyMon1Exp + call BattleMonPartyAttr + + ; current exp - base exp + ld b, h + ld c, l + ld hl, wEXPBarBaseEXP + ld de, wEXPBarCurEXP + call SubThreeByteNum + + ; exp needed - base exp + ld bc, hMultiplicand + ld hl, wEXPBarBaseEXP + ld de, wEXPBarNeededEXP + call SubThreeByteNum + + ; make the divisor an 8-bit number + ld hl, wEXPBarNeededEXP + ld de, wEXPBarCurEXP + 1 + ld a, [hli] + and a + jr z, .twoBytes + ld a, [hli] + ld [hld], a + dec hl + ld a, [hli] + ld [hld], a + ld a, [de] + inc de + ld [de], a + dec de + dec de + ld a, [de] + inc de + ld [de], a + dec de + xor a + ld [hli], a + ld [de], a + inc de +.twoBytes + ld a, [hl] + and a + jr z, .oneByte + srl a + ld [hli], a + ld a, [hl] + rr a + ld [hld], a + ld a, [de] + srl a + ld [de], a + inc de + ld a, [de] + rr a + ld [de], a + dec de + jr .twoBytes +.oneByte + + ; current exp * (8 tiles * 8 pixels) + ld hl, hMultiplicand + ld de, wEXPBarCurEXP + ld a, [de] + inc de + ld [hli], a + ld a, [de] + inc de + ld [hli], a + ld a, [de] + ld [hl], a + ld a, 8 * 8 + ldh [hMultiplier], a + call Multiply + + ; product / needed exp = pixel length + ld a, [wEXPBarNeededEXP + 2] + ldh [hDivisor], a + ld b, 4 + jp Divide + +; calculates the three byte number starting at [bc] +; minus the three byte number starting at [hl] +; and stores it into the three bytes starting at [de] +; assumes that [hl] is smaller than [bc] +SubThreeByteNum: + call .subByte + call .subByte +.subByte + ld a, [bc] + inc bc + sub [hl] + inc hl + ld [de], a + jr nc, .noCarry + dec de + ld a, [de] + dec a + ld [de], a + inc de +.noCarry + inc de + ret + +; return the address of the BattleMon's party struct attribute in hl +BattleMonPartyAttr: + ld a, [wPlayerMonNumber] + ld bc, wPartyMon2 - wPartyMon1 + jp AddNTimes + +AnimateEXPBarAgain: + call IsCurrentMonBattleMon + ret nz + xor a + ld [wEXPBarPixelLength], a + hlcoord 17, 11 + ld a, EXP_BAR_BASE_TILE_ID + ld c, 8 +.loop + ld [hld], a + dec c + jr nz, .loop +AnimateEXPBar: + call IsCurrentMonBattleMon + ret nz + ld a, SFX_HEAL_HP + call PlaySoundWaitForCurrent + call CalcEXPBarPixelLength + ld hl, wEXPBarPixelLength + ld a, [hl] + ld b, a + ldh a, [hQuotient + 3] + ld [hl], a + sub b + jr z, .done + ld b, a + ld c, 8 + hlcoord 17, 11 +.loop1 + ld a, [hl] + cp EXP_BAR_BASE_TILE_ID + 8 + jr nz, .loop2 + dec hl + dec c + jr z, .done + jr .loop1 +.loop2 + inc a + ld [hl], a + call DelayFrame + dec b + jr z, .done + jr .loop1 +.done + ld bc, 8 + hlcoord 10, 11 + ld de, wTileMapBackup + 10 + 11 * 20 + call CopyData + ld c, 32 + jp DelayFrames + +KeepEXPBarFull: + call IsCurrentMonBattleMon + ret nz + ld a, [wEXPBarKeepFullFlag] + set 0, a + ld [wEXPBarKeepFullFlag], a + ret + +IsCurrentMonBattleMon: + ld a, [wPlayerMonNumber] + ld b, a + ld a, [wWhichPokemon] + cp b + ret diff --git a/gfx/battle/exp_bar.png b/gfx/battle/exp_bar.png new file mode 100644 index 0000000000..539be56f9a Binary files /dev/null and b/gfx/battle/exp_bar.png differ diff --git a/gfx/font.asm b/gfx/font.asm index daff363295..e3267415d8 100644 --- a/gfx/font.asm +++ b/gfx/font.asm @@ -29,3 +29,6 @@ WorldMapTileGraphicsEnd: PlayerCharacterTitleGraphics: INCBIN "gfx/title/player.2bpp" PlayerCharacterTitleGraphicsEnd: + +EXPBarGraphics:: INCBIN "gfx/battle/exp_bar.2bpp" +EXPBarGraphicsEnd:: diff --git a/home/load_font.asm b/home/load_font.asm index 0f48e84caa..01612042fe 100644 --- a/home/load_font.asm +++ b/home/load_font.asm @@ -31,17 +31,30 @@ LoadTextBoxTilePatterns:: jp CopyVideoData ; if LCD is on, transfer during V-blank LoadHpBarAndStatusTilePatterns:: - ldh a, [rLCDC] - bit rLCDC_ENABLE, a - jr nz, .on -.off - ld hl, HpBarAndStatusGraphics - ld de, vChars2 tile $62 - ld bc, HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics - ld a, BANK(HpBarAndStatusGraphics) - jp FarCopyData2 ; if LCD is off, transfer all at once -.on ld de, HpBarAndStatusGraphics ld hl, vChars2 tile $62 lb bc, BANK(HpBarAndStatusGraphics), (HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics) / $10 - jp CopyVideoData ; if LCD is on, transfer during V-blank + call GoodCopyVideoData + ld de, EXPBarGraphics + ld hl, vChars1 tile $40 + lb bc, BANK(EXPBarGraphics), (EXPBarGraphicsEnd - EXPBarGraphics) / $10 + jp GoodCopyVideoData + +GoodCopyVideoData: + ldh a, [rLCDC] + bit rLCDC_ENABLE, a + jp nz, CopyVideoData ; if LCD is on, transfer during V-blank + ld a, b + push hl + push de + ld h, 0 + ld l, c + add hl, hl + add hl, hl + add hl, hl + add hl, hl + ld b, h + ld c, l + pop hl + pop de + jp FarCopyData2 ; if LCD is off, transfer all at once diff --git a/main.asm b/main.asm index 11ee2fa9f9..878e77357f 100644 --- a/main.asm +++ b/main.asm @@ -251,6 +251,7 @@ INCLUDE "engine/events/hidden_objects/indigo_plateau_hq.asm" SECTION "Battle Engine 9", ROMX INCLUDE "engine/battle/experience.asm" +INCLUDE "engine/gfx/exp_bar.asm" SECTION "Diploma", ROMX diff --git a/ram/wram.asm b/ram/wram.asm index 8a774edf8c..781c11392d 100644 --- a/ram/wram.asm +++ b/ram/wram.asm @@ -2226,6 +2226,12 @@ wBoxMonNicksEnd:: wBoxDataEnd:: +wEXPBarPixelLength:: ds 1 +wEXPBarBaseEXP:: ds 3 +wEXPBarCurEXP:: ds 3 +wEXPBarNeededEXP:: ds 3 +wEXPBarKeepFullFlag:: ds 1 + SECTION "Stack", WRAM0