diff options
Diffstat (limited to 'engine/pokemon')
| -rw-r--r-- | engine/pokemon/add_mon.asm | 516 | ||||
| -rw-r--r-- | engine/pokemon/bills_pc.asm | 548 | ||||
| -rwxr-xr-x | engine/pokemon/evos_moves.asm | 513 | ||||
| -rwxr-xr-x | engine/pokemon/experience.asm | 149 | ||||
| -rwxr-xr-x | engine/pokemon/learn_move.asm | 226 | ||||
| -rw-r--r-- | engine/pokemon/load_mon_data.asm | 49 | ||||
| -rw-r--r-- | engine/pokemon/remove_mon.asm | 95 | ||||
| -rwxr-xr-x | engine/pokemon/set_types.asm | 15 | ||||
| -rwxr-xr-x | engine/pokemon/status_ailments.asm | 46 | ||||
| -rwxr-xr-x | engine/pokemon/status_screen.asm | 481 |
10 files changed, 2638 insertions, 0 deletions
diff --git a/engine/pokemon/add_mon.asm b/engine/pokemon/add_mon.asm new file mode 100644 index 00000000..7627136b --- /dev/null +++ b/engine/pokemon/add_mon.asm @@ -0,0 +1,516 @@ +_AddPartyMon:: +; Adds a new mon to the player's or enemy's party. +; [wMonDataLocation] is used in an unusual way in this function. +; If the lower nybble is 0, the mon is added to the player's party, else the enemy's. +; If the entire value is 0, then the player is allowed to name the mon. + ld de, wPartyCount + ld a, [wMonDataLocation] + and $f + jr z, .next + ld de, wEnemyPartyCount +.next + ld a, [de] + inc a + cp PARTY_LENGTH + 1 + ret nc ; return if the party is already full + ld [de], a + ld a, [de] + ld [hNewPartyLength], a + add e + ld e, a + jr nc, .noCarry + inc d +.noCarry + ld a, [wcf91] + ld [de], a ; write species of new mon in party list + inc de + ld a, $ff ; terminator + ld [de], a + ld hl, wPartyMonOT + ld a, [wMonDataLocation] + and $f + jr z, .next2 + ld hl, wEnemyMonOT +.next2 + ld a, [hNewPartyLength] + dec a + call SkipFixedLengthTextEntries + ld d, h + ld e, l + ld hl, wPlayerName + ld bc, NAME_LENGTH + call CopyData + ld a, [wMonDataLocation] + and a + jr nz, .skipNaming + ld hl, wPartyMonNicks + ld a, [hNewPartyLength] + dec a + call SkipFixedLengthTextEntries + ld a, NAME_MON_SCREEN + ld [wNamingScreenType], a + predef AskName +.skipNaming + ld hl, wPartyMons + ld a, [wMonDataLocation] + and $f + jr z, .next3 + ld hl, wEnemyMons +.next3 + ld a, [hNewPartyLength] + dec a + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld e, l + ld d, h + push hl + ld a, [wcf91] + ld [wd0b5], a + call GetMonHeader + ld hl, wMonHeader + ld a, [hli] + ld [de], a ; species + inc de + pop hl + push hl + ld a, [wMonDataLocation] + and $f + ld a, $98 ; set enemy trainer mon IVs to fixed average values + ld b, $88 + jr nz, .next4 + +; If the mon is being added to the player's party, update the pokedex. + ld a, [wcf91] + ld [wd11e], a + push de + predef IndexToPokedex + pop de + ld a, [wd11e] + dec a + ld c, a + ld b, FLAG_TEST + ld hl, wPokedexOwned + call FlagAction + ld a, c ; whether the mon was already flagged as owned + ld [wUnusedD153], a ; not read + ld a, [wd11e] + dec a + ld c, a + ld b, FLAG_SET + push bc + call FlagAction + pop bc + ld hl, wPokedexSeen + call FlagAction + + pop hl + push hl + + ld a, [wIsInBattle] + and a ; is this a wild mon caught in battle? + jr nz, .copyEnemyMonData + +; Not wild. + call Random ; generate random IVs + ld b, a + call Random + +.next4 + push bc + ld bc, wPartyMon1DVs - wPartyMon1 + add hl, bc + pop bc + ld [hli], a + ld [hl], b ; write IVs + ld bc, (wPartyMon1HPExp - 1) - (wPartyMon1DVs + 1) + add hl, bc + ld a, 1 + ld c, a + xor a + ld b, a + call CalcStat ; calc HP stat (set cur Hp to max HP) + ld a, [H_MULTIPLICAND+1] + ld [de], a + inc de + ld a, [H_MULTIPLICAND+2] + ld [de], a + inc de + xor a + ld [de], a ; box level + inc de + ld [de], a ; status ailments + inc de + jr .copyMonTypesAndMoves +.copyEnemyMonData + ld bc, wEnemyMon1DVs - wEnemyMon1 + add hl, bc + ld a, [wEnemyMonDVs] ; copy IVs from cur enemy mon + ld [hli], a + ld a, [wEnemyMonDVs + 1] + ld [hl], a + ld a, [wEnemyMonHP] ; copy HP from cur enemy mon + ld [de], a + inc de + ld a, [wEnemyMonHP+1] + ld [de], a + inc de + xor a + ld [de], a ; box level + inc de + ld a, [wEnemyMonStatus] ; copy status ailments from cur enemy mon + ld [de], a + inc de +.copyMonTypesAndMoves + ld hl, wMonHTypes + ld a, [hli] ; type 1 + ld [de], a + inc de + ld a, [hli] ; type 2 + ld [de], a + inc de + ld a, [hli] ; catch rate (held item in gen 2) + ld [de], a + ld hl, wMonHMoves + ld a, [hli] + inc de + push de + ld [de], a + ld a, [hli] + inc de + ld [de], a + ld a, [hli] + inc de + ld [de], a + ld a, [hli] + inc de + ld [de], a + push de + dec de + dec de + dec de + xor a + ld [wLearningMovesFromDayCare], a + predef WriteMonMoves + pop de + ld a, [wPlayerID] ; set trainer ID to player ID + inc de + ld [de], a + ld a, [wPlayerID + 1] + inc de + ld [de], a + push de + ld a, [wCurEnemyLVL] + ld d, a + callab CalcExperience + pop de + inc de + ld a, [hExperience] ; write experience + ld [de], a + inc de + ld a, [hExperience + 1] + ld [de], a + inc de + ld a, [hExperience + 2] + ld [de], a + xor a + ld b, NUM_STATS * 2 +.writeEVsLoop ; set all EVs to 0 + inc de + ld [de], a + dec b + jr nz, .writeEVsLoop + inc de + inc de + pop hl + call AddPartyMon_WriteMovePP + inc de + ld a, [wCurEnemyLVL] + ld [de], a + inc de + ld a, [wIsInBattle] + dec a + jr nz, .calcFreshStats + ld hl, wEnemyMonMaxHP + ld bc, $a + call CopyData ; copy stats of cur enemy mon + pop hl + jr .done +.calcFreshStats + pop hl + ld bc, wPartyMon1HPExp - 1 - wPartyMon1 + add hl, bc + ld b, $0 + call CalcStats ; calculate fresh set of stats +.done + scf + ret + +LoadMovePPs: + call GetPredefRegisters + ; fallthrough +AddPartyMon_WriteMovePP: + ld b, NUM_MOVES +.pploop + ld a, [hli] ; read move ID + and a + jr z, .empty + dec a + push hl + push de + push bc + ld hl, Moves + ld bc, MoveEnd - Moves + call AddNTimes + ld de, wcd6d + ld a, BANK(Moves) + call FarCopyData + pop bc + pop de + pop hl + ld a, [wcd6d + 5] ; PP is byte 5 of move data +.empty + inc de + ld [de], a + dec b + jr nz, .pploop ; there are still moves to read + ret + +; adds enemy mon [wcf91] (at position [wWhichPokemon] in enemy list) to own party +; used in the cable club trade center +_AddEnemyMonToPlayerParty:: + ld hl, wPartyCount + ld a, [hl] + cp PARTY_LENGTH + scf + ret z ; party full, return failure + inc a + ld [hl], a ; add 1 to party members + ld c, a + ld b, $0 + add hl, bc + ld a, [wcf91] + ld [hli], a ; add mon as last list entry + ld [hl], $ff ; write new sentinel + ld hl, wPartyMons + ld a, [wPartyCount] + dec a + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld e, l + ld d, h + ld hl, wLoadedMon + call CopyData ; write new mon's data (from wLoadedMon) + ld hl, wPartyMonOT + ld a, [wPartyCount] + dec a + call SkipFixedLengthTextEntries + ld d, h + ld e, l + ld hl, wEnemyMonOT + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries + ld bc, NAME_LENGTH + call CopyData ; write new mon's OT name (from an enemy mon) + ld hl, wPartyMonNicks + ld a, [wPartyCount] + dec a + call SkipFixedLengthTextEntries + ld d, h + ld e, l + ld hl, wEnemyMonNicks + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries + ld bc, NAME_LENGTH + call CopyData ; write new mon's nickname (from an enemy mon) + ld a, [wcf91] + ld [wd11e], a + predef IndexToPokedex + ld a, [wd11e] + dec a + ld c, a + ld b, FLAG_SET + ld hl, wPokedexOwned + push bc + call FlagAction ; add to owned pokemon + pop bc + ld hl, wPokedexSeen + call FlagAction ; add to seen pokemon + and a + ret ; return success + +_MoveMon:: + ld a, [wMoveMonType] + and a ; BOX_TO_PARTY + jr z, .checkPartyMonSlots + cp DAYCARE_TO_PARTY + jr z, .checkPartyMonSlots + cp PARTY_TO_DAYCARE + ld hl, wDayCareMon + jr z, .findMonDataSrc + ; else it's PARTY_TO_BOX + ld hl, wNumInBox + ld a, [hl] + cp MONS_PER_BOX + jr nz, .partyOrBoxNotFull + jr .boxFull +.checkPartyMonSlots + ld hl, wPartyCount + ld a, [hl] + cp PARTY_LENGTH + jr nz, .partyOrBoxNotFull +.boxFull + scf + ret +.partyOrBoxNotFull + inc a + ld [hl], a ; increment number of mons in party/box + ld c, a + ld b, 0 + add hl, bc + ld a, [wMoveMonType] + cp DAYCARE_TO_PARTY + ld a, [wDayCareMon] + jr z, .copySpecies + ld a, [wcf91] +.copySpecies + ld [hli], a ; write new mon ID + ld [hl], $ff ; write new sentinel +.findMonDataDest + ld a, [wMoveMonType] + dec a + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 ; $2c + ld a, [wPartyCount] + jr nz, .addMonOffset + ; if it's PARTY_TO_BOX + ld hl, wBoxMons + ld bc, wBoxMon2 - wBoxMon1 ; $21 + ld a, [wNumInBox] +.addMonOffset + dec a + call AddNTimes +.findMonDataSrc + push hl + ld e, l + ld d, h + ld a, [wMoveMonType] + and a + ld hl, wBoxMons + ld bc, wBoxMon2 - wBoxMon1 ; $21 + jr z, .addMonOffset2 + cp DAYCARE_TO_PARTY + ld hl, wDayCareMon + jr z, .copyMonData + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 ; $2c +.addMonOffset2 + ld a, [wWhichPokemon] + call AddNTimes +.copyMonData + push hl + push de + ld bc, wBoxMon2 - wBoxMon1 + call CopyData + pop de + pop hl + ld a, [wMoveMonType] + and a ; BOX_TO_PARTY + jr z, .findOTdest + cp DAYCARE_TO_PARTY + jr z, .findOTdest + ld bc, wBoxMon2 - wBoxMon1 + add hl, bc + ld a, [hl] ; hl = Level + inc de + inc de + inc de + ld [de], a ; de = BoxLevel +.findOTdest + ld a, [wMoveMonType] + cp PARTY_TO_DAYCARE + ld de, wDayCareMonOT + jr z, .findOTsrc + dec a + ld hl, wPartyMonOT + ld a, [wPartyCount] + jr nz, .addOToffset + ld hl, wBoxMonOT + ld a, [wNumInBox] +.addOToffset + dec a + call SkipFixedLengthTextEntries + ld d, h + ld e, l +.findOTsrc + ld hl, wBoxMonOT + ld a, [wMoveMonType] + and a + jr z, .addOToffset2 + ld hl, wDayCareMonOT + cp DAYCARE_TO_PARTY + jr z, .copyOT + ld hl, wPartyMonOT +.addOToffset2 + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries +.copyOT + ld bc, NAME_LENGTH + call CopyData + ld a, [wMoveMonType] +.findNickDest + cp PARTY_TO_DAYCARE + ld de, wDayCareMonName + jr z, .findNickSrc + dec a + ld hl, wPartyMonNicks + ld a, [wPartyCount] + jr nz, .addNickOffset + ld hl, wBoxMonNicks + ld a, [wNumInBox] +.addNickOffset + dec a + call SkipFixedLengthTextEntries + ld d, h + ld e, l +.findNickSrc + ld hl, wBoxMonNicks + ld a, [wMoveMonType] + and a + jr z, .addNickOffset2 + ld hl, wDayCareMonName + cp DAYCARE_TO_PARTY + jr z, .copyNick + ld hl, wPartyMonNicks +.addNickOffset2 + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries +.copyNick + ld bc, NAME_LENGTH + call CopyData + pop hl + ld a, [wMoveMonType] + cp PARTY_TO_BOX + jr z, .done + cp PARTY_TO_DAYCARE + jr z, .done + push hl + srl a + add $2 + ld [wMonDataLocation], a + call LoadMonData + callba CalcLevelFromExperience + ld a, d + ld [wCurEnemyLVL], a + pop hl + ld bc, wBoxMon2 - wBoxMon1 + add hl, bc + ld [hli], a + ld d, h + ld e, l + ld bc, -18 + add hl, bc + ld b, $1 + call CalcStats +.done + and a + ret diff --git a/engine/pokemon/bills_pc.asm b/engine/pokemon/bills_pc.asm new file mode 100644 index 00000000..e5855f1d --- /dev/null +++ b/engine/pokemon/bills_pc.asm @@ -0,0 +1,548 @@ +DisplayPCMainMenu:: + xor a + ld [H_AUTOBGTRANSFERENABLED], a + call SaveScreenTilesToBuffer2 + ld a, [wNumHoFTeams] + and a + jr nz, .leaguePCAvailable + CheckEvent EVENT_GOT_POKEDEX + jr z, .noOaksPC + ld a, [wNumHoFTeams] + and a + jr nz, .leaguePCAvailable + coord hl, 0, 0 + ld b, 8 + ld c, 14 + jr .next +.noOaksPC + coord hl, 0, 0 + ld b, 6 + ld c, 14 + jr .next +.leaguePCAvailable + coord hl, 0, 0 + ld b, 10 + ld c, 14 +.next + call TextBoxBorder + call UpdateSprites + ld a, 3 + ld [wMaxMenuItem], a + CheckEvent EVENT_MET_BILL + jr nz, .metBill + coord hl, 2, 2 + ld de, SomeonesPCText + jr .next2 +.metBill + coord hl, 2, 2 + ld de, BillsPCText +.next2 + call PlaceString + coord hl, 2, 4 + ld de, wPlayerName + call PlaceString + ld l, c + ld h, b + ld de, PlayersPCText + call PlaceString + CheckEvent EVENT_GOT_POKEDEX + jr z, .noOaksPC2 + coord hl, 2, 6 + ld de, OaksPCText + call PlaceString + ld a, [wNumHoFTeams] + and a + jr z, .noLeaguePC + ld a, 4 + ld [wMaxMenuItem], a + coord hl, 2, 8 + ld de, PKMNLeaguePCText + call PlaceString + coord hl, 2, 10 + ld de, LogOffPCText + jr .next3 +.noLeaguePC + coord hl, 2, 8 + ld de, LogOffPCText + jr .next3 +.noOaksPC2 + ld a, $2 + ld [wMaxMenuItem], a + coord hl, 2, 6 + ld de, LogOffPCText +.next3 + call PlaceString + ld a, A_BUTTON | B_BUTTON + ld [wMenuWatchedKeys], a + ld a, 2 + ld [wTopMenuItemY], a + ld a, 1 + ld [wTopMenuItemX], a + xor a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + ret + +SomeonesPCText: db "SOMEONE's PC@" +BillsPCText: db "BILL's PC@" +PlayersPCText: db "'s PC@" +OaksPCText: db "PROF.OAK's PC@" +PKMNLeaguePCText: db "<pkmn>LEAGUE@" +LogOffPCText: db "LOG OFF@" + +BillsPC_:: + ld hl, wd730 + set 6, [hl] + xor a + ld [wParentMenuItem], a + inc a ; MONSTER_NAME + ld [wNameListType], a + call LoadHpBarAndStatusTilePatterns + ld a, [wListScrollOffset] + push af + ld a, [wFlags_0xcd60] + bit 3, a ; accessing Bill's PC through another PC? + jr nz, BillsPCMenu +; accessing it directly + ld a, SFX_TURN_ON_PC + call PlaySound + ld hl, SwitchOnText + call PrintText + +BillsPCMenu: + ld a, [wParentMenuItem] + ld [wCurrentMenuItem], a + ld hl, vChars2 + $780 + ld de, PokeballTileGraphics + lb bc, BANK(PokeballTileGraphics), $01 + call CopyVideoData + call LoadScreenTilesFromBuffer2DisableBGTransfer + coord hl, 0, 0 + ld b, 10 + ld c, 12 + call TextBoxBorder + coord hl, 2, 2 + ld de, BillsPCMenuText + call PlaceString + ld hl, wTopMenuItemY + ld a, 2 + ld [hli], a ; wTopMenuItemY + dec a + ld [hli], a ; wTopMenuItemX + inc hl + inc hl + ld a, 4 + ld [hli], a ; wMaxMenuItem + ld a, A_BUTTON | B_BUTTON + ld [hli], a ; wMenuWatchedKeys + xor a + ld [hli], a ; wLastMenuItem + ld [hli], a ; wPartyAndBillsPCSavedMenuItem + ld hl, wListScrollOffset + ld [hli], a ; wListScrollOffset + ld [hl], a ; wMenuWatchMovingOutOfBounds + ld [wPlayerMonNumber], a + ld hl, WhatText + call PrintText + coord hl, 9, 14 + ld b, 2 + ld c, 9 + call TextBoxBorder + ld a, [wCurrentBoxNum] + and $7f + cp 9 + jr c, .singleDigitBoxNum +; two digit box num + sub 9 + coord hl, 17, 16 + ld [hl], "1" + add "0" + jr .next +.singleDigitBoxNum + add "1" +.next + Coorda 18, 16 + coord hl, 10, 16 + ld de, BoxNoPCText + call PlaceString + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + call HandleMenuInput + bit 1, a + jp nz, ExitBillsPC ; b button + call PlaceUnfilledArrowMenuCursor + ld a, [wCurrentMenuItem] + ld [wParentMenuItem], a + and a + jp z, BillsPCWithdraw ; withdraw + cp $1 + jp z, BillsPCDeposit ; deposit + cp $2 + jp z, BillsPCRelease ; release + cp $3 + jp z, BillsPCChangeBox ; change box + +ExitBillsPC: + ld a, [wFlags_0xcd60] + bit 3, a ; accessing Bill's PC through another PC? + jr nz, .next +; accessing it directly + call LoadTextBoxTilePatterns + ld a, SFX_TURN_OFF_PC + call PlaySound + call WaitForSoundToFinish +.next + ld hl, wFlags_0xcd60 + res 5, [hl] + call LoadScreenTilesFromBuffer2 + pop af + ld [wListScrollOffset], a + ld hl, wd730 + res 6, [hl] + ret + +BillsPCDeposit: + ld a, [wPartyCount] + dec a + jr nz, .partyLargeEnough + ld hl, CantDepositLastMonText + call PrintText + jp BillsPCMenu +.partyLargeEnough + ld a, [wNumInBox] + cp MONS_PER_BOX + jr nz, .boxNotFull + ld hl, BoxFullText + call PrintText + jp BillsPCMenu +.boxNotFull + ld hl, wPartyCount + call DisplayMonListMenu + jp c, BillsPCMenu + call DisplayDepositWithdrawMenu + jp nc, BillsPCMenu + ld a, [wcf91] + call GetCryData + call PlaySoundWaitForCurrent + ld a, PARTY_TO_BOX + ld [wMoveMonType], a + call MoveMon + xor a + ld [wRemoveMonFromBox], a + call RemovePokemon + call WaitForSoundToFinish + ld hl, wBoxNumString + ld a, [wCurrentBoxNum] + and $7f + cp 9 + jr c, .singleDigitBoxNum + sub 9 + ld [hl], "1" + inc hl + add "0" + jr .next +.singleDigitBoxNum + add "1" +.next + ld [hli], a + ld [hl], "@" + ld hl, MonWasStoredText + call PrintText + jp BillsPCMenu + +BillsPCWithdraw: + ld a, [wNumInBox] + and a + jr nz, .boxNotEmpty + ld hl, NoMonText + call PrintText + jp BillsPCMenu +.boxNotEmpty + ld a, [wPartyCount] + cp PARTY_LENGTH + jr nz, .partyNotFull + ld hl, CantTakeMonText + call PrintText + jp BillsPCMenu +.partyNotFull + ld hl, wNumInBox + call DisplayMonListMenu + jp c, BillsPCMenu + call DisplayDepositWithdrawMenu + jp nc, BillsPCMenu + ld a, [wWhichPokemon] + ld hl, wBoxMonNicks + call GetPartyMonName + ld a, [wcf91] + call GetCryData + call PlaySoundWaitForCurrent + xor a ; BOX_TO_PARTY + ld [wMoveMonType], a + call MoveMon + ld a, 1 + ld [wRemoveMonFromBox], a + call RemovePokemon + call WaitForSoundToFinish + ld hl, MonIsTakenOutText + call PrintText + jp BillsPCMenu + +BillsPCRelease: + ld a, [wNumInBox] + and a + jr nz, .loop + ld hl, NoMonText + call PrintText + jp BillsPCMenu +.loop + ld hl, wNumInBox + call DisplayMonListMenu + jp c, BillsPCMenu + ld hl, OnceReleasedText + call PrintText + call YesNoChoice + ld a, [wCurrentMenuItem] + and a + jr nz, .loop + inc a + ld [wRemoveMonFromBox], a + call RemovePokemon + call WaitForSoundToFinish + ld a, [wcf91] + call PlayCry + ld hl, MonWasReleasedText + call PrintText + jp BillsPCMenu + +BillsPCChangeBox: + callba ChangeBox + jp BillsPCMenu + +DisplayMonListMenu: + ld a, l + ld [wListPointer], a + ld a, h + ld [wListPointer + 1], a + xor a + ld [wPrintItemPrices], a + ld [wListMenuID], a + inc a ; MONSTER_NAME + ld [wNameListType], a + ld a, [wPartyAndBillsPCSavedMenuItem] + ld [wCurrentMenuItem], a + call DisplayListMenuID + ld a, [wCurrentMenuItem] + ld [wPartyAndBillsPCSavedMenuItem], a + ret + +BillsPCMenuText: + db "WITHDRAW <pkmn>" + next "DEPOSIT <pkmn>" + next "RELEASE <pkmn>" + next "CHANGE BOX" + next "SEE YA!" + db "@" + +BoxNoPCText: + db "BOX No.@" + +KnowsHMMove:: +; returns whether mon with party index [wWhichPokemon] knows an HM move + ld hl, wPartyMon1Moves + ld bc, wPartyMon2 - wPartyMon1 + jr .next +; unreachable + ld hl, wBoxMon1Moves + ld bc, wBoxMon2 - wBoxMon1 +.next + ld a, [wWhichPokemon] + call AddNTimes + ld b, NUM_MOVES +.loop + ld a, [hli] + push hl + push bc + ld hl, HMMoveArray + ld de, 1 + call IsInArray + pop bc + pop hl + ret c + dec b + jr nz, .loop + and a + ret + +INCLUDE "data/hm_moves.asm" + +DisplayDepositWithdrawMenu: + coord hl, 9, 10 + ld b, 6 + ld c, 9 + call TextBoxBorder + ld a, [wParentMenuItem] + and a ; was the Deposit or Withdraw item selected in the parent menu? + ld de, DepositPCText + jr nz, .next + ld de, WithdrawPCText +.next + coord hl, 11, 12 + call PlaceString + coord hl, 11, 14 + ld de, StatsCancelPCText + call PlaceString + ld hl, wTopMenuItemY + ld a, 12 + ld [hli], a ; wTopMenuItemY + ld a, 10 + ld [hli], a ; wTopMenuItemX + xor a + ld [hli], a ; wCurrentMenuItem + inc hl + ld a, 2 + ld [hli], a ; wMaxMenuItem + ld a, A_BUTTON | B_BUTTON + ld [hli], a ; wMenuWatchedKeys + xor a + ld [hl], a ; wLastMenuItem + ld hl, wListScrollOffset + ld [hli], a ; wListScrollOffset + ld [hl], a ; wMenuWatchMovingOutOfBounds + ld [wPlayerMonNumber], a + ld [wPartyAndBillsPCSavedMenuItem], a +.loop + call HandleMenuInput + bit 1, a ; pressed B? + jr nz, .exit + ld a, [wCurrentMenuItem] + and a + jr z, .choseDepositWithdraw + dec a + jr z, .viewStats +.exit + and a + ret +.choseDepositWithdraw + scf + ret +.viewStats + call SaveScreenTilesToBuffer1 + ld a, [wParentMenuItem] + and a + ld a, PLAYER_PARTY_DATA + jr nz, .next2 + ld a, BOX_DATA +.next2 + ld [wMonDataLocation], a + predef StatusScreen + predef StatusScreen2 + call LoadScreenTilesFromBuffer1 + call ReloadTilesetTilePatterns + call RunDefaultPaletteCommand + call LoadGBPal + jr .loop + +DepositPCText: db "DEPOSIT@" +WithdrawPCText: db "WITHDRAW@" +StatsCancelPCText: + db "STATS" + next "CANCEL@" + +SwitchOnText: + TX_FAR _SwitchOnText + db "@" + +WhatText: + TX_FAR _WhatText + db "@" + +DepositWhichMonText: + TX_FAR _DepositWhichMonText + db "@" + +MonWasStoredText: + TX_FAR _MonWasStoredText + db "@" + +CantDepositLastMonText: + TX_FAR _CantDepositLastMonText + db "@" + +BoxFullText: + TX_FAR _BoxFullText + db "@" + +MonIsTakenOutText: + TX_FAR _MonIsTakenOutText + db "@" + +NoMonText: + TX_FAR _NoMonText + db "@" + +CantTakeMonText: + TX_FAR _CantTakeMonText + db "@" + +ReleaseWhichMonText: + TX_FAR _ReleaseWhichMonText + db "@" + +OnceReleasedText: + TX_FAR _OnceReleasedText + db "@" + +MonWasReleasedText: + TX_FAR _MonWasReleasedText + db "@" + +CableClubLeftGameboy:: + ld a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + ret z + ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + cp SPRITE_FACING_RIGHT + ret nz + ld a, [wCurMap] + cp TRADE_CENTER + ld a, LINK_STATE_START_TRADE + jr z, .next + inc a ; LINK_STATE_START_BATTLE +.next + ld [wLinkState], a + call EnableAutoTextBoxDrawing + tx_pre_jump JustAMomentText + +CableClubRightGameboy:: + ld a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + ret z + ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + cp SPRITE_FACING_LEFT + ret nz + ld a, [wCurMap] + cp TRADE_CENTER + ld a, LINK_STATE_START_TRADE + jr z, .next + inc a ; LINK_STATE_START_BATTLE +.next + ld [wLinkState], a + call EnableAutoTextBoxDrawing + tx_pre_jump JustAMomentText + +JustAMomentText:: + TX_FAR _JustAMomentText + db "@" + + ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + cp SPRITE_FACING_UP + ret nz + call EnableAutoTextBoxDrawing + tx_pre_jump OpenBillsPCText + +OpenBillsPCText:: + TX_BILLS_PC + diff --git a/engine/pokemon/evos_moves.asm b/engine/pokemon/evos_moves.asm new file mode 100755 index 00000000..f50f8081 --- /dev/null +++ b/engine/pokemon/evos_moves.asm @@ -0,0 +1,513 @@ +; try to evolve the mon in [wWhichPokemon] +TryEvolvingMon: + ld hl, wCanEvolveFlags + xor a + ld [hl], a + ld a, [wWhichPokemon] + ld c, a + ld b, FLAG_SET + call Evolution_FlagAction + +; this is only called after battle +; it is supposed to do level up evolutions, though there is a bug that allows item evolutions to occur +EvolutionAfterBattle: + ld a, [hTilesetType] + push af + xor a + ld [wEvolutionOccurred], a + dec a + ld [wWhichPokemon], a + push hl + push bc + push de + ld hl, wPartyCount + push hl + +Evolution_PartyMonLoop: ; loop over party mons + ld hl, wWhichPokemon + inc [hl] + pop hl + inc hl + ld a, [hl] + cp $ff ; have we reached the end of the party? + jp z, .done + ld [wEvoOldSpecies], a + push hl + ld a, [wWhichPokemon] + ld c, a + ld hl, wCanEvolveFlags + ld b, FLAG_TEST + call Evolution_FlagAction + ld a, c + and a ; is the mon's bit set? + jp z, Evolution_PartyMonLoop ; if not, go to the next mon + ld a, [wEvoOldSpecies] + dec a + ld b, 0 + ld hl, EvosMovesPointerTable + add a + rl b + ld c, a + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + push hl + ld a, [wcf91] + push af + xor a ; PLAYER_PARTY_DATA + ld [wMonDataLocation], a + call LoadMonData + pop af + ld [wcf91], a + pop hl + +.evoEntryLoop ; loop over evolution entries + ld a, [hli] + and a ; have we reached the end of the evolution data? + jr z, Evolution_PartyMonLoop + ld b, a ; evolution type + cp EV_TRADE + jr z, .checkTradeEvo +; not trade evolution + ld a, [wLinkState] + cp LINK_STATE_TRADING + jr z, Evolution_PartyMonLoop ; if trading, go the next mon + ld a, b + cp EV_ITEM + jr z, .checkItemEvo + ld a, [wForceEvolution] + and a + jr nz, Evolution_PartyMonLoop + ld a, b + cp EV_LEVEL + jr z, .checkLevel +.checkTradeEvo + ld a, [wLinkState] + cp LINK_STATE_TRADING + jp nz, .nextEvoEntry1 ; if not trading, go to the next evolution entry + ld a, [hli] ; level requirement + ld b, a + ld a, [wLoadedMonLevel] + cp b ; is the mon's level greater than the evolution requirement? + jp c, Evolution_PartyMonLoop ; if so, go the next mon + jr .doEvolution +.checkItemEvo + ld a, [hli] + ld b, a ; evolution item + ld a, [wcf91] ; this is supposed to be the last item used, but it is also used to hold species numbers + cp b ; was the evolution item in this entry used? + jp nz, .nextEvoEntry1 ; if not, go to the next evolution entry +.checkLevel + ld a, [hli] ; level requirement + ld b, a + ld a, [wLoadedMonLevel] + cp b ; is the mon's level greater than the evolution requirement? + jp c, .nextEvoEntry2 ; if so, go the next evolution entry +.doEvolution + ld [wCurEnemyLVL], a + ld a, 1 + ld [wEvolutionOccurred], a + push hl + ld a, [hl] + ld [wEvoNewSpecies], a + ld a, [wWhichPokemon] + ld hl, wPartyMonNicks + call GetPartyMonName + call CopyStringToCF4B + ld hl, IsEvolvingText + call PrintText + ld c, 50 + call DelayFrames + xor a + ld [H_AUTOBGTRANSFERENABLED], a + coord hl, 0, 0 + lb bc, 12, 20 + call ClearScreenArea + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + ld a, $ff + ld [wUpdateSpritesEnabled], a + call ClearSprites + callab EvolveMon + jp c, CancelledEvolution + ld hl, EvolvedText + call PrintText + pop hl + ld a, [hl] + ld [wd0b5], a + ld [wLoadedMonSpecies], a + ld [wEvoNewSpecies], a + ld a, MONSTER_NAME + ld [wNameListType], a + ld a, BANK(TrainerNames) ; bank is not used for monster names + ld [wPredefBank], a + call GetName + push hl + ld hl, IntoText + call PrintText_NoCreatingTextBox + ld a, SFX_GET_ITEM_2 + call PlaySoundWaitForCurrent + call WaitForSoundToFinish + ld c, 40 + call DelayFrames + call ClearScreen + call RenameEvolvedMon + ld a, [wd11e] + push af + ld a, [wd0b5] + ld [wd11e], a + predef IndexToPokedex + ld a, [wd11e] + dec a + ld hl, BaseStats + ld bc, MonBaseStatsEnd - MonBaseStats + call AddNTimes + ld de, wMonHeader + call CopyData + ld a, [wd0b5] + ld [wMonHIndex], a + pop af + ld [wd11e], a + ld hl, wLoadedMonHPExp - 1 + ld de, wLoadedMonStats + ld b, $1 + call CalcStats + ld a, [wWhichPokemon] + ld hl, wPartyMon1 + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld e, l + ld d, h + push hl + push bc + ld bc, wPartyMon1MaxHP - wPartyMon1 + add hl, bc + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, wLoadedMonMaxHP + 1 + ld a, [hld] + sub c + ld c, a + ld a, [hl] + sbc b + ld b, a + ld hl, wLoadedMonHP + 1 + ld a, [hl] + add c + ld [hld], a + ld a, [hl] + adc b + ld [hl], a + dec hl + pop bc + call CopyData + ld a, [wd0b5] + ld [wd11e], a + xor a + ld [wMonDataLocation], a + call LearnMoveFromLevelUp + pop hl + predef SetPartyMonTypes + ld a, [wIsInBattle] + and a + call z, Evolution_ReloadTilesetTilePatterns + predef IndexToPokedex + ld a, [wd11e] + dec a + ld c, a + ld b, FLAG_SET + ld hl, wPokedexOwned + push bc + call Evolution_FlagAction + pop bc + ld hl, wPokedexSeen + call Evolution_FlagAction + pop de + pop hl + ld a, [wLoadedMonSpecies] + ld [hl], a + push hl + ld l, e + ld h, d + jr .nextEvoEntry2 + +.nextEvoEntry1 + inc hl + +.nextEvoEntry2 + inc hl + jp .evoEntryLoop + +.done + pop de + pop bc + pop hl + pop af + ld [hTilesetType], a + ld a, [wLinkState] + cp LINK_STATE_TRADING + ret z + ld a, [wIsInBattle] + and a + ret nz + ld a, [wEvolutionOccurred] + and a + call nz, PlayDefaultMusic + ret + +RenameEvolvedMon: +; Renames the mon to its new, evolved form's standard name unless it had a +; nickname, in which case the nickname is kept. + ld a, [wd0b5] + push af + ld a, [wMonHIndex] + ld [wd0b5], a + call GetName + pop af + ld [wd0b5], a + ld hl, wcd6d + ld de, wcf4b +.compareNamesLoop + ld a, [de] + inc de + cp [hl] + inc hl + ret nz + cp "@" + jr nz, .compareNamesLoop + ld a, [wWhichPokemon] + ld bc, NAME_LENGTH + ld hl, wPartyMonNicks + call AddNTimes + push hl + call GetName + ld hl, wcd6d + pop de + jp CopyData + +CancelledEvolution: + ld hl, StoppedEvolvingText + call PrintText + call ClearScreen + pop hl + call Evolution_ReloadTilesetTilePatterns + jp Evolution_PartyMonLoop + +EvolvedText: + TX_FAR _EvolvedText + db "@" + +IntoText: + TX_FAR _IntoText + db "@" + +StoppedEvolvingText: + TX_FAR _StoppedEvolvingText + db "@" + +IsEvolvingText: + TX_FAR _IsEvolvingText + db "@" + +Evolution_ReloadTilesetTilePatterns: + ld a, [wLinkState] + cp LINK_STATE_TRADING + ret z + jp ReloadTilesetTilePatterns + +LearnMoveFromLevelUp: + ld hl, EvosMovesPointerTable + ld a, [wd11e] ; species + ld [wcf91], a + dec a + ld bc, 0 + ld hl, EvosMovesPointerTable + add a + rl b + ld c, a + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a +.skipEvolutionDataLoop ; loop to skip past the evolution data, which comes before the move data + ld a, [hli] + and a ; have we reached the end of the evolution data? + jr nz, .skipEvolutionDataLoop ; if not, jump back up +.learnSetLoop ; loop over the learn set until we reach a move that is learnt at the current level or the end of the list + ld a, [hli] + and a ; have we reached the end of the learn set? + jr z, .done ; if we've reached the end of the learn set, jump + ld b, a ; level the move is learnt at + ld a, [wCurEnemyLVL] + cp b ; is the move learnt at the mon's current level? + ld a, [hli] ; move ID + jr nz, .learnSetLoop + ld d, a ; ID of move to learn + ld a, [wMonDataLocation] + and a + jr nz, .next +; If [wMonDataLocation] is 0 (PLAYER_PARTY_DATA), get the address of the mon's +; current moves in party data. Every call to this function sets +; [wMonDataLocation] to 0 because other data locations are not supported. +; If it is not 0, this function will not work properly. + ld hl, wPartyMon1Moves + ld a, [wWhichPokemon] + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes +.next + ld b, NUM_MOVES +.checkCurrentMovesLoop ; check if the move to learn is already known + ld a, [hli] + cp d + jr z, .done ; if already known, jump + dec b + jr nz, .checkCurrentMovesLoop + ld a, d + ld [wMoveNum], a + ld [wd11e], a + call GetMoveName + call CopyStringToCF4B + predef LearnMove +.done + ld a, [wcf91] + ld [wd11e], a + ret + +; writes the moves a mon has at level [wCurEnemyLVL] to [de] +; move slots are being filled up sequentially and shifted if all slots are full +WriteMonMoves: + call GetPredefRegisters + push hl + push de + push bc + ld hl, EvosMovesPointerTable + ld b, 0 + ld a, [wcf91] ; cur mon ID + dec a + add a + rl b + ld c, a + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a +.skipEvoEntriesLoop + ld a, [hli] + and a + jr nz, .skipEvoEntriesLoop + jr .firstMove +.nextMove + pop de +.nextMove2 + inc hl +.firstMove + ld a, [hli] ; read level of next move in learnset + and a + jp z, .done ; end of list + ld b, a + ld a, [wCurEnemyLVL] + cp b + jp c, .done ; mon level < move level (assumption: learnset is sorted by level) + ld a, [wLearningMovesFromDayCare] + and a + jr z, .skipMinLevelCheck + ld a, [wDayCareStartLevel] + cp b + jr nc, .nextMove2 ; min level >= move level + +.skipMinLevelCheck + +; check if the move is already known + push de + ld c, NUM_MOVES +.alreadyKnowsCheckLoop + ld a, [de] + inc de + cp [hl] + jr z, .nextMove + dec c + jr nz, .alreadyKnowsCheckLoop + +; try to find an empty move slot + pop de + push de + ld c, NUM_MOVES +.findEmptySlotLoop + ld a, [de] + and a + jr z, .writeMoveToSlot2 + inc de + dec c + jr nz, .findEmptySlotLoop + +; no empty move slots found + pop de + push de + push hl + ld h, d + ld l, e + call WriteMonMoves_ShiftMoveData ; shift all moves one up (deleting move 1) + ld a, [wLearningMovesFromDayCare] + and a + jr z, .writeMoveToSlot + +; shift PP as well if learning moves from day care + push de + ld bc, wPartyMon1PP - (wPartyMon1Moves + 3) + add hl, bc + ld d, h + ld e, l + call WriteMonMoves_ShiftMoveData ; shift all move PP data one up + pop de + +.writeMoveToSlot + pop hl +.writeMoveToSlot2 + ld a, [hl] + ld [de], a + ld a, [wLearningMovesFromDayCare] + and a + jr z, .nextMove + +; write move PP value if learning moves from day care + push hl + ld a, [hl] + ld hl, wPartyMon1PP - wPartyMon1Moves + add hl, de + push hl + dec a + ld hl, Moves + ld bc, MoveEnd - Moves + call AddNTimes + ld de, wBuffer + ld a, BANK(Moves) + call FarCopyData + ld a, [wBuffer + 5] + pop hl + ld [hl], a + pop hl + jr .nextMove + +.done + pop bc + pop de + pop hl + ret + +; shifts all move data one up (freeing 4th move slot) +WriteMonMoves_ShiftMoveData: + ld c, NUM_MOVES - 1 +.loop + inc de + ld a, [de] + ld [hli], a + dec c + jr nz, .loop + ret + +Evolution_FlagAction: + predef_jump FlagActionPredef + +INCLUDE "data/evos_moves.asm" diff --git a/engine/pokemon/experience.asm b/engine/pokemon/experience.asm new file mode 100755 index 00000000..3ee4b2a8 --- /dev/null +++ b/engine/pokemon/experience.asm @@ -0,0 +1,149 @@ +; calculates the level a mon should be based on its current exp +CalcLevelFromExperience:: + ld a, [wLoadedMonSpecies] + ld [wd0b5], a + call GetMonHeader + ld d, $1 ; init level to 1 +.loop + inc d ; increment level + call CalcExperience + push hl + ld hl, wLoadedMonExp + 2 ; current exp +; compare exp needed for level d with current exp + ld a, [hExperience + 2] + ld c, a + ld a, [hld] + sub c + ld a, [hExperience + 1] + ld c, a + ld a, [hld] + sbc c + ld a, [hExperience] + ld c, a + ld a, [hl] + sbc c + pop hl + jr nc, .loop ; if exp needed for level d is not greater than exp, try the next level + dec d ; since the exp was too high on the last loop iteration, go back to the previous value and return + ret + +; calculates the amount of experience needed for level d +CalcExperience:: + ld a, [wMonHGrowthRate] + add a + add a + ld c, a + ld b, 0 + ld hl, GrowthRateTable + add hl, bc + call CalcDSquared + ld a, d + ld [H_MULTIPLIER], a + call Multiply + ld a, [hl] + and $f0 + swap a + ld [H_MULTIPLIER], a + call Multiply + ld a, [hli] + and $f + ld [H_DIVISOR], a + ld b, $4 + call Divide + ld a, [H_QUOTIENT + 1] + push af + ld a, [H_QUOTIENT + 2] + push af + ld a, [H_QUOTIENT + 3] + push af + call CalcDSquared + ld a, [hl] + and $7f + ld [H_MULTIPLIER], a + call Multiply + ld a, [H_PRODUCT + 1] + push af + ld a, [H_PRODUCT + 2] + push af + ld a, [H_PRODUCT + 3] + push af + ld a, [hli] + push af + xor a + ld [H_MULTIPLICAND], a + ld [H_MULTIPLICAND + 1], a + ld a, d + ld [H_MULTIPLICAND + 2], a + ld a, [hli] + ld [H_MULTIPLIER], a + call Multiply + ld b, [hl] + ld a, [H_PRODUCT + 3] + sub b + ld [H_PRODUCT + 3], a + ld b, $0 + ld a, [H_PRODUCT + 2] + sbc b + ld [H_PRODUCT + 2], a + ld a, [H_PRODUCT + 1] + sbc b + ld [H_PRODUCT + 1], a +; The difference of the linear term and the constant term consists of 3 bytes +; starting at H_PRODUCT + 1. Below, hExperience (an alias of that address) will +; be used instead for the further work of adding or subtracting the squared +; term and adding the cubed term. + pop af + and $80 + jr nz, .subtractSquaredTerm ; check sign + pop bc + ld a, [hExperience + 2] + add b + ld [hExperience + 2], a + pop bc + ld a, [hExperience + 1] + adc b + ld [hExperience + 1], a + pop bc + ld a, [hExperience] + adc b + ld [hExperience], a + jr .addCubedTerm +.subtractSquaredTerm + pop bc + ld a, [hExperience + 2] + sub b + ld [hExperience + 2], a + pop bc + ld a, [hExperience + 1] + sbc b + ld [hExperience + 1], a + pop bc + ld a, [hExperience] + sbc b + ld [hExperience], a +.addCubedTerm + pop bc + ld a, [hExperience + 2] + add b + ld [hExperience + 2], a + pop bc + ld a, [hExperience + 1] + adc b + ld [hExperience + 1], a + pop bc + ld a, [hExperience] + adc b + ld [hExperience], a + ret + +; calculates d*d +CalcDSquared: + xor a + ld [H_MULTIPLICAND], a + ld [H_MULTIPLICAND + 1], a + ld a, d + ld [H_MULTIPLICAND + 2], a + ld [H_MULTIPLIER], a + jp Multiply + +INCLUDE "data/growth_rates.asm" diff --git a/engine/pokemon/learn_move.asm b/engine/pokemon/learn_move.asm new file mode 100755 index 00000000..53c7f87e --- /dev/null +++ b/engine/pokemon/learn_move.asm @@ -0,0 +1,226 @@ +LearnMove: + call SaveScreenTilesToBuffer1 + ld a, [wWhichPokemon] + ld hl, wPartyMonNicks + call GetPartyMonName + ld hl, wcd6d + ld de, wLearnMoveMonName + ld bc, NAME_LENGTH + call CopyData + +DontAbandonLearning: + ld hl, wPartyMon1Moves + ld bc, wPartyMon2Moves - wPartyMon1Moves + ld a, [wWhichPokemon] + call AddNTimes + ld d, h + ld e, l + ld b, NUM_MOVES +.findEmptyMoveSlotLoop + ld a, [hl] + and a + jr z, .next + inc hl + dec b + jr nz, .findEmptyMoveSlotLoop + push de + call TryingToLearn + pop de + jp c, AbandonLearning + push hl + push de + ld [wd11e], a + call GetMoveName + ld hl, OneTwoAndText + call PrintText + pop de + pop hl +.next + ld a, [wMoveNum] + ld [hl], a + ld bc, wPartyMon1PP - wPartyMon1Moves + add hl, bc + push hl + push de + dec a + ld hl, Moves + ld bc, MoveEnd - Moves + call AddNTimes + ld de, wBuffer + ld a, BANK(Moves) + call FarCopyData + ld a, [wBuffer + 5] ; a = move's max PP + pop de + pop hl + ld [hl], a + ld a, [wIsInBattle] + and a + jp z, PrintLearnedMove + ld a, [wWhichPokemon] + ld b, a + ld a, [wPlayerMonNumber] + cp b + jp nz, PrintLearnedMove + ld h, d + ld l, e + ld de, wBattleMonMoves + ld bc, NUM_MOVES + call CopyData + ld bc, wPartyMon1PP - wPartyMon1OTID + add hl, bc + ld de, wBattleMonPP + ld bc, NUM_MOVES + call CopyData + jp PrintLearnedMove + +AbandonLearning: + ld hl, AbandonLearningText + call PrintText + coord hl, 14, 7 + lb bc, 8, 15 + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID ; yes/no menu + ld a, [wCurrentMenuItem] + and a + jp nz, DontAbandonLearning + ld hl, DidNotLearnText + call PrintText + ld b, 0 + ret + +PrintLearnedMove: + ld hl, LearnedMove1Text + call PrintText + ld b, 1 + ret + +TryingToLearn: + push hl + ld hl, TryingToLearnText + call PrintText + coord hl, 14, 7 + lb bc, 8, 15 + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID ; yes/no menu + pop hl + ld a, [wCurrentMenuItem] + rra + ret c + ld bc, -NUM_MOVES + add hl, bc + push hl + ld de, wMoves + ld bc, NUM_MOVES + call CopyData + callab FormatMovesString + pop hl +.loop + push hl + ld hl, WhichMoveToForgetText + call PrintText + coord hl, 4, 7 + ld b, 4 + ld c, 14 + call TextBoxBorder + coord hl, 6, 8 + ld de, wMovesString + ld a, [hFlags_0xFFF6] + set 2, a + ld [hFlags_0xFFF6], a + call PlaceString + ld a, [hFlags_0xFFF6] + res 2, a + ld [hFlags_0xFFF6], a + ld hl, wTopMenuItemY + ld a, 8 + ld [hli], a ; wTopMenuItemY + ld a, 5 + ld [hli], a ; wTopMenuItemX + xor a + ld [hli], a ; wCurrentMenuItem + inc hl + ld a, [wNumMovesMinusOne] + ld [hli], a ; wMaxMenuItem + ld a, A_BUTTON | B_BUTTON + ld [hli], a ; wMenuWatchedKeys + ld [hl], 0 ; wLastMenuItem + ld hl, hFlags_0xFFF6 + set 1, [hl] + call HandleMenuInput + ld hl, hFlags_0xFFF6 + res 1, [hl] + push af + call LoadScreenTilesFromBuffer1 + pop af + pop hl + bit 1, a ; pressed b + jr nz, .cancel + push hl + ld a, [wCurrentMenuItem] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + push af + push bc + call IsMoveHM + pop bc + pop de + ld a, d + jr c, .hm + pop hl + add hl, bc + and a + ret +.hm + ld hl, HMCantDeleteText + call PrintText + pop hl + jr .loop +.cancel + scf + ret + +LearnedMove1Text: + TX_FAR _LearnedMove1Text + TX_SFX_ITEM_1 ; plays SFX_GET_ITEM_1 in the party menu (rare candy) and plays SFX_LEVEL_UP in battle + TX_BLINK + db "@" + +WhichMoveToForgetText: + TX_FAR _WhichMoveToForgetText + db "@" + +AbandonLearningText: + TX_FAR _AbandonLearningText + db "@" + +DidNotLearnText: + TX_FAR _DidNotLearnText + db "@" + +TryingToLearnText: + TX_FAR _TryingToLearnText + db "@" + +OneTwoAndText: + TX_FAR _OneTwoAndText + TX_DELAY + TX_ASM + ld a, SFX_SWAP + call PlaySoundWaitForCurrent + ld hl, PoofText + ret + +PoofText: + TX_FAR _PoofText + TX_DELAY +ForgotAndText: + TX_FAR _ForgotAndText + db "@" + +HMCantDeleteText: + TX_FAR _HMCantDeleteText + db "@" diff --git a/engine/pokemon/load_mon_data.asm b/engine/pokemon/load_mon_data.asm new file mode 100644 index 00000000..480ab1ca --- /dev/null +++ b/engine/pokemon/load_mon_data.asm @@ -0,0 +1,49 @@ +LoadMonData_:: +; Load monster [wWhichPokemon] from list [wMonDataLocation]: +; 0: partymon +; 1: enemymon +; 2: boxmon +; 3: daycaremon +; Return monster id at wcf91 and its data at wLoadedMon. +; Also load base stats at wMonHeader for convenience. + + ld a, [wDayCareMonSpecies] + ld [wcf91], a + ld a, [wMonDataLocation] + cp DAYCARE_DATA + jr z, .GetMonHeader + + ld a, [wWhichPokemon] + ld e, a + callab GetMonSpecies + +.GetMonHeader + ld a, [wcf91] + ld [wd0b5], a ; input for GetMonHeader + call GetMonHeader + + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 + ld a, [wMonDataLocation] + cp ENEMY_PARTY_DATA + jr c, .getMonEntry + + ld hl, wEnemyMons + jr z, .getMonEntry + + cp 2 + ld hl, wBoxMons + ld bc, wBoxMon2 - wBoxMon1 + jr z, .getMonEntry + + ld hl, wDayCareMon + jr .copyMonData + +.getMonEntry + ld a, [wWhichPokemon] + call AddNTimes + +.copyMonData + ld de, wLoadedMon + ld bc, wPartyMon2 - wPartyMon1 + jp CopyData diff --git a/engine/pokemon/remove_mon.asm b/engine/pokemon/remove_mon.asm new file mode 100644 index 00000000..6f7e91d6 --- /dev/null +++ b/engine/pokemon/remove_mon.asm @@ -0,0 +1,95 @@ +_RemovePokemon:: + ld hl, wPartyCount + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7b74 + ld hl, wNumInBox +.asm_7b74 + ld a, [hl] + dec a + ld [hli], a + ld a, [wWhichPokemon] + ld c, a + ld b, $0 + add hl, bc + ld e, l + ld d, h + inc de +.asm_7b81 + ld a, [de] + inc de + ld [hli], a + inc a + jr nz, .asm_7b81 + ld hl, wPartyMonOT + ld d, $5 + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7b97 + ld hl, wBoxMonOT + ld d, $13 +.asm_7b97 + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries + ld a, [wWhichPokemon] + cp d + jr nz, .asm_7ba6 + ld [hl], $ff + ret +.asm_7ba6 + ld d, h + ld e, l + ld bc, NAME_LENGTH + add hl, bc + ld bc, wPartyMonNicks + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7bb8 + ld bc, wBoxMonNicks +.asm_7bb8 + call CopyDataUntil + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7bcd + ld hl, wBoxMons + ld bc, wBoxMon2 - wBoxMon1 +.asm_7bcd + ld a, [wWhichPokemon] + call AddNTimes + ld d, h + ld e, l + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7be4 + ld bc, wBoxMon2 - wBoxMon1 + add hl, bc + ld bc, wBoxMonOT + jr .asm_7beb +.asm_7be4 + ld bc, wPartyMon2 - wPartyMon1 + add hl, bc + ld bc, wPartyMonOT +.asm_7beb + call CopyDataUntil + ld hl, wPartyMonNicks + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7bfa + ld hl, wBoxMonNicks +.asm_7bfa + ld bc, NAME_LENGTH + ld a, [wWhichPokemon] + call AddNTimes + ld d, h + ld e, l + ld bc, NAME_LENGTH + add hl, bc + ld bc, wPokedexOwned + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7c15 + ld bc, wBoxMonNicksEnd +.asm_7c15 + jp CopyDataUntil diff --git a/engine/pokemon/set_types.asm b/engine/pokemon/set_types.asm new file mode 100755 index 00000000..e9235f13 --- /dev/null +++ b/engine/pokemon/set_types.asm @@ -0,0 +1,15 @@ +; updates the types of a party mon (pointed to in hl) to the ones of the mon specified in wd11e +SetPartyMonTypes: + call GetPredefRegisters + ld bc, wPartyMon1Type - wPartyMon1 ; $5 + add hl, bc + ld a, [wd11e] + ld [wd0b5], a + push hl + call GetMonHeader + pop hl + ld a, [wMonHType1] + ld [hli], a + ld a, [wMonHType2] + ld [hl], a + ret diff --git a/engine/pokemon/status_ailments.asm b/engine/pokemon/status_ailments.asm new file mode 100755 index 00000000..3da1fc43 --- /dev/null +++ b/engine/pokemon/status_ailments.asm @@ -0,0 +1,46 @@ +PrintStatusAilment:: + ld a, [de] + bit PSN, a + jr nz, .psn + bit BRN, a + jr nz, .brn + bit FRZ, a + jr nz, .frz + bit PAR, a + jr nz, .par + and SLP + ret z + ld a, "S" + ld [hli], a + ld a, "L" + ld [hli], a + ld [hl], "P" + ret +.psn + ld a, "P" + ld [hli], a + ld a, "S" + ld [hli], a + ld [hl], "N" + ret +.brn + ld a, "B" + ld [hli], a + ld a, "R" + ld [hli], a + ld [hl], "N" + ret +.frz + ld a, "F" + ld [hli], a + ld a, "R" + ld [hli], a + ld [hl], "Z" + ret +.par + ld a, "P" + ld [hli], a + ld a, "A" + ld [hli], a + ld [hl], "R" + ret diff --git a/engine/pokemon/status_screen.asm b/engine/pokemon/status_screen.asm new file mode 100755 index 00000000..20bee0ee --- /dev/null +++ b/engine/pokemon/status_screen.asm @@ -0,0 +1,481 @@ +DrawHP: +; Draws the HP bar in the stats screen + call GetPredefRegisters + ld a, $1 + jr DrawHP_ + +DrawHP2: +; Draws the HP bar in the party screen + call GetPredefRegisters + ld a, $2 + +DrawHP_: + ld [wHPBarType], a + push hl + ld a, [wLoadedMonHP] + ld b, a + ld a, [wLoadedMonHP + 1] + ld c, a + or b + jr nz, .nonzeroHP + xor a + ld c, a + ld e, a + ld a, $6 + ld d, a + jp .drawHPBarAndPrintFraction +.nonzeroHP + ld a, [wLoadedMonMaxHP] + ld d, a + ld a, [wLoadedMonMaxHP + 1] + ld e, a + predef HPBarLength + ld a, $6 + ld d, a + ld c, a +.drawHPBarAndPrintFraction + pop hl + push de + push hl + push hl + call DrawHPBar + pop hl + ld a, [hFlags_0xFFF6] + bit 0, a + jr z, .printFractionBelowBar + ld bc, $9 ; right of bar + jr .printFraction +.printFractionBelowBar + ld bc, SCREEN_WIDTH + 1 ; below bar +.printFraction + add hl, bc + ld de, wLoadedMonHP + lb bc, 2, 3 + call PrintNumber + ld a, "/" + ld [hli], a + ld de, wLoadedMonMaxHP + lb bc, 2, 3 + call PrintNumber + pop hl + pop de + ret + + +; Predef 0x37 +StatusScreen: + call LoadMonData + ld a, [wMonDataLocation] + cp BOX_DATA + jr c, .DontRecalculate +; mon is in a box or daycare + ld a, [wLoadedMonBoxLevel] + ld [wLoadedMonLevel], a + ld [wCurEnemyLVL], a + ld hl, wLoadedMonHPExp - 1 + ld de, wLoadedMonStats + ld b, $1 + call CalcStats ; Recalculate stats +.DontRecalculate + ld hl, wd72c + set 1, [hl] + ld a, $33 + ld [rNR50], a ; Reduce the volume + call GBPalWhiteOutWithDelay3 + call ClearScreen + call UpdateSprites + call LoadHpBarAndStatusTilePatterns + ld de, BattleHudTiles1 ; source + ld hl, vChars2 + $6d0 ; dest + lb bc, BANK(BattleHudTiles1), $03 + call CopyVideoDataDouble ; ·│ :L and halfarrow line end + ld de, BattleHudTiles2 + ld hl, vChars2 + $780 + lb bc, BANK(BattleHudTiles2), $01 + call CopyVideoDataDouble ; │ + ld de, BattleHudTiles3 + ld hl, vChars2 + $760 + lb bc, BANK(BattleHudTiles3), $02 + call CopyVideoDataDouble ; ─┘ + ld de, PTile + ld hl, vChars2 + $720 + lb bc, BANK(PTile), (PTileEnd - PTile) / $8 + call CopyVideoDataDouble ; P (for PP), inline + ld a, [hTilesetType] + push af + xor a + ld [hTilesetType], a + coord hl, 19, 1 + lb bc, 6, 10 + call DrawLineBox ; Draws the box around name, HP and status + ld de, -6 + add hl, de + ld [hl], "⠄" ; . after No ("." is a different one) + dec hl + ld [hl], "№" + coord hl, 19, 9 + lb bc, 8, 6 + call DrawLineBox ; Draws the box around types, ID No. and OT + coord hl, 10, 9 + ld de, Type1Text + call PlaceString ; "TYPE1/" + coord hl, 11, 3 + predef DrawHP + ld hl, wStatusScreenHPBarColor + call GetHealthBarColor + ld b, SET_PAL_STATUS_SCREEN + call RunPaletteCommand + coord hl, 16, 6 + ld de, wLoadedMonStatus + call PrintStatusCondition + jr nz, .StatusWritten + coord hl, 16, 6 + ld de, OKText + call PlaceString ; "OK" +.StatusWritten + coord hl, 9, 6 + ld de, StatusText + call PlaceString ; "STATUS/" + coord hl, 14, 2 + call PrintLevel ; Pokémon level + ld a, [wMonHIndex] + ld [wd11e], a + ld [wd0b5], a + predef IndexToPokedex + coord hl, 3, 7 + ld de, wd11e + lb bc, LEADING_ZEROES | 1, 3 + call PrintNumber ; Pokémon no. + coord hl, 11, 10 + predef PrintMonType + ld hl, NamePointers2 + call .GetStringPointer + ld d, h + ld e, l + coord hl, 9, 1 + call PlaceString ; Pokémon name + ld hl, OTPointers + call .GetStringPointer + ld d, h + ld e, l + coord hl, 12, 16 + call PlaceString ; OT + coord hl, 12, 14 + ld de, wLoadedMonOTID + lb bc, LEADING_ZEROES | 2, 5 + call PrintNumber ; ID Number + ld d, $0 + call PrintStatsBox + call Delay3 + call GBPalNormal + coord hl, 1, 0 + call LoadFlippedFrontSpriteByMonIndex ; draw Pokémon picture + ld a, [wcf91] + call PlayCry ; play Pokémon cry + call WaitForTextScrollButtonPress ; wait for button + pop af + ld [hTilesetType], a + ret + +.GetStringPointer + ld a, [wMonDataLocation] + add a + ld c, a + ld b, 0 + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wMonDataLocation] + cp DAYCARE_DATA + ret z + ld a, [wWhichPokemon] + jp SkipFixedLengthTextEntries + +OTPointers: + dw wPartyMonOT + dw wEnemyMonOT + dw wBoxMonOT + dw wDayCareMonOT + +NamePointers2: + dw wPartyMonNicks + dw wEnemyMonNicks + dw wBoxMonNicks + dw wDayCareMonName + +Type1Text: + db "TYPE1/", $4e + +Type2Text: + db "TYPE2/", $4e + +IDNoText: + db $73, "№/", $4e + +OTText: + db "OT/" + next "@" + +StatusText: + db "STATUS/@" + +OKText: + db "OK@" + +; Draws a line starting from hl high b and wide c +DrawLineBox: + ld de, SCREEN_WIDTH ; New line +.PrintVerticalLine + ld [hl], $78 ; │ + add hl, de + dec b + jr nz, .PrintVerticalLine + ld [hl], $77 ; ┘ + dec hl +.PrintHorizLine + ld [hl], $76 ; ─ + dec hl + dec c + jr nz, .PrintHorizLine + ld [hl], $6f ; ← (halfarrow ending) + ret + +PTile: + INCBIN "gfx/font/P.1bpp" +PTileEnd: + +PrintStatsBox: + ld a, d + and a ; a is 0 from the status screen + jr nz, .DifferentBox + coord hl, 0, 8 + ld b, 8 + ld c, 8 + call TextBoxBorder ; Draws the box + coord hl, 1, 9 ; Start printing stats from here + ld bc, $0019 ; Number offset + jr .PrintStats +.DifferentBox + coord hl, 9, 2 + ld b, 8 + ld c, 9 + call TextBoxBorder + coord hl, 11, 3 + ld bc, $0018 +.PrintStats + push bc + push hl + ld de, StatsText + call PlaceString + pop hl + pop bc + add hl, bc + ld de, wLoadedMonAttack + lb bc, 2, 3 + call PrintStat + ld de, wLoadedMonDefense + call PrintStat + ld de, wLoadedMonSpeed + call PrintStat + ld de, wLoadedMonSpecial + jp PrintNumber +PrintStat: + push hl + call PrintNumber + pop hl + ld de, SCREEN_WIDTH * 2 + add hl, de + ret + +StatsText: + db "ATTACK" + next "DEFENSE" + next "SPEED" + next "SPECIAL@" + +StatusScreen2: + ld a, [hTilesetType] + push af + xor a + ld [hTilesetType], a + ld [H_AUTOBGTRANSFERENABLED], a + ld bc, NUM_MOVES + 1 + ld hl, wMoves + call FillMemory + ld hl, wLoadedMonMoves + ld de, wMoves + ld bc, NUM_MOVES + call CopyData + callab FormatMovesString + coord hl, 9, 2 + lb bc, 5, 10 + call ClearScreenArea ; Clear under name + coord hl, 19, 3 + ld [hl], $78 + coord hl, 0, 8 + ld b, 8 + ld c, 18 + call TextBoxBorder ; Draw move container + coord hl, 2, 9 + ld de, wMovesString + call PlaceString ; Print moves + ld a, [wNumMovesMinusOne] + inc a + ld c, a + ld a, $4 + sub c + ld b, a ; Number of moves ? + coord hl, 11, 10 + ld de, SCREEN_WIDTH * 2 + ld a, $72 ; special P tile id + call StatusScreen_PrintPP ; Print "PP" + ld a, b + and a + jr z, .InitPP + ld c, a + ld a, "-" + call StatusScreen_PrintPP ; Fill the rest with -- +.InitPP + ld hl, wLoadedMonMoves + coord de, 14, 10 + ld b, 0 +.PrintPP + ld a, [hli] + and a + jr z, .PPDone + push bc + push hl + push de + ld hl, wCurrentMenuItem + ld a, [hl] + push af + ld a, b + ld [hl], a + push hl + callab GetMaxPP + pop hl + pop af + ld [hl], a + pop de + pop hl + push hl + ld bc, wPartyMon1PP - wPartyMon1Moves - 1 + add hl, bc + ld a, [hl] + and $3f + ld [wStatusScreenCurrentPP], a + ld h, d + ld l, e + push hl + ld de, wStatusScreenCurrentPP + lb bc, 1, 2 + call PrintNumber + ld a, "/" + ld [hli], a + ld de, wMaxPP + lb bc, 1, 2 + call PrintNumber + pop hl + ld de, SCREEN_WIDTH * 2 + add hl, de + ld d, h + ld e, l + pop hl + pop bc + inc b + ld a, b + cp $4 + jr nz, .PrintPP +.PPDone + coord hl, 9, 3 + ld de, StatusScreenExpText + call PlaceString + ld a, [wLoadedMonLevel] + push af + cp MAX_LEVEL + jr z, .Level100 + inc a + ld [wLoadedMonLevel], a ; Increase temporarily if not 100 +.Level100 + coord hl, 14, 6 + ld [hl], $70 ; 1-tile "to" + inc hl + inc hl + call PrintLevel + pop af + ld [wLoadedMonLevel], a + ld de, wLoadedMonExp + coord hl, 12, 4 + lb bc, 3, 7 + call PrintNumber ; exp + call CalcExpToLevelUp + ld de, wLoadedMonExp + coord hl, 7, 6 + lb bc, 3, 7 + call PrintNumber ; exp needed to level up + coord hl, 9, 0 + call StatusScreen_ClearName + coord hl, 9, 1 + call StatusScreen_ClearName + ld a, [wMonHIndex] + ld [wd11e], a + call GetMonName + coord hl, 9, 1 + call PlaceString + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + call WaitForTextScrollButtonPress ; wait for button + pop af + ld [hTilesetType], a + ld hl, wd72c + res 1, [hl] + ld a, $77 + ld [rNR50], a + call GBPalWhiteOut + jp ClearScreen + +CalcExpToLevelUp: + ld a, [wLoadedMonLevel] + cp MAX_LEVEL + jr z, .atMaxLevel + inc a + ld d, a + callab CalcExperience + ld hl, wLoadedMonExp + 2 + ld a, [hExperience + 2] + sub [hl] + ld [hld], a + ld a, [hExperience + 1] + sbc [hl] + ld [hld], a + ld a, [hExperience] + sbc [hl] + ld [hld], a + ret +.atMaxLevel + ld hl, wLoadedMonExp + xor a + ld [hli], a + ld [hli], a + ld [hl], a + ret + +StatusScreenExpText: + db "EXP POINTS" + next "LEVEL UP@" + +StatusScreen_ClearName: + ld bc, 10 + ld a, " " + jp FillMemory + +StatusScreen_PrintPP: +; print PP or -- c times, going down two rows each time + ld [hli], a + ld [hld], a + add hl, de + dec c + jr nz, StatusScreen_PrintPP + ret |
