diff options
-rw-r--r-- | constants/misc_constants.asm | 8 | ||||
-rwxr-xr-x | engine/battle/core.asm | 20 | ||||
-rw-r--r-- | engine/battle/init_battle_variables.asm | 2 | ||||
-rwxr-xr-x | engine/hidden_object_functions17.asm | 48 | ||||
-rwxr-xr-x | engine/hidden_object_functions7.asm | 14 | ||||
-rwxr-xr-x | engine/items/items.asm | 396 | ||||
-rwxr-xr-x | engine/menu/main_menu.asm | 4 | ||||
-rwxr-xr-x | engine/menu/naming_screen.asm | 2 | ||||
-rwxr-xr-x | engine/menu/start_sub_menus.asm | 2 | ||||
-rwxr-xr-x | engine/oak_speech.asm | 2 | ||||
-rw-r--r-- | engine/overworld/movement.asm | 11 | ||||
-rwxr-xr-x | engine/town_map.asm | 10 | ||||
-rw-r--r-- | home.asm | 6 | ||||
-rw-r--r-- | home/overworld.asm | 4 | ||||
-rwxr-xr-x | main.asm | 17 | ||||
-rwxr-xr-x | scripts/halloffameroom.asm | 4 | ||||
-rwxr-xr-x | scripts/viridiancity.asm | 2 | ||||
-rwxr-xr-x | wram.asm | 59 |
18 files changed, 400 insertions, 211 deletions
diff --git a/constants/misc_constants.asm b/constants/misc_constants.asm index b42745cc..c9240ad7 100644 --- a/constants/misc_constants.asm +++ b/constants/misc_constants.asm @@ -10,6 +10,9 @@ PARTY_LENGTH EQU 6 MONS_PER_BOX EQU 20 NUM_BOXES EQU 12 +BAG_ITEM_CAPACITY EQU 20 +PC_ITEM_CAPACITY EQU 50 + HOF_MON EQU $10 HOF_TEAM EQU PARTY_LENGTH * HOF_MON HOF_TEAM_CAPACITY EQU 50 @@ -169,6 +172,11 @@ HP_BAR_RED EQU 2 ; D733 flags BIT_TEST_BATTLE EQU 0 +; battle type constants +BATTLE_TYPE_NORMAL EQU 0 +BATTLE_TYPE_OLD_MAN EQU 1 +BATTLE_TYPE_SAFARI EQU 2 + ; serial ESTABLISH_CONNECTION_WITH_INTERNAL_CLOCK EQU $01 diff --git a/engine/battle/core.asm b/engine/battle/core.asm index 0b534dda..a00d15bb 100755 --- a/engine/battle/core.asm +++ b/engine/battle/core.asm @@ -1584,7 +1584,7 @@ TryRunningFromBattle: ; 3cab9 (f:4ab9) call IsGhostBattle jp z, .canEscape ; jump if it's a ghost battle ld a, [W_BATTLETYPE] - cp $2 + cp BATTLE_TYPE_SAFARI jp z, .canEscape ; jump if it's a safari battle ld a, [wLinkState] cp LINK_STATE_BATTLING @@ -2094,7 +2094,7 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) call SaveScreenTilesToBuffer1 .nonstandardbattle ld a, [W_BATTLETYPE] - cp $2 ; safari + cp BATTLE_TYPE_SAFARI ld a, BATTLE_MENU_TEMPLATE jr nz, .menuselected ld a, SAFARI_BATTLE_MENU_TEMPLATE @@ -2144,7 +2144,7 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) jr .rightColumn .leftColumn ; put cursor in left column of menu ld a, [W_BATTLETYPE] - cp $2 + cp BATTLE_TYPE_SAFARI ld a, " " jr z, .safariLeftColumn ; put cursor in left column for normal battle menu (i.e. when it's not a Safari battle) @@ -2177,7 +2177,7 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) jr .AButtonPressed ; the A button was pressed .rightColumn ; put cursor in right column of menu ld a, [W_BATTLETYPE] - cp $2 + cp BATTLE_TYPE_SAFARI ld a, " " jr z, .safariRightColumn ; put cursor in right column for normal battle menu (i.e. when it's not a Safari battle) @@ -2214,7 +2214,7 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) .AButtonPressed call PlaceUnfilledArrowMenuCursor ld a, [W_BATTLETYPE] - cp $2 ; is it a Safari battle? + cp BATTLE_TYPE_SAFARI ld a, [wCurrentMenuItem] ld [wBattleAndStartSavedMenuItem], a jr z, .handleMenuSelection @@ -2236,7 +2236,7 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) jr nz, .upperLeftMenuItemWasNotSelected ; the upper left menu item was selected ld a, [W_BATTLETYPE] - cp $2 + cp BATTLE_TYPE_SAFARI jr z, .throwSafariBallWasSelected ; the "FIGHT" menu was selected xor a @@ -2264,7 +2264,7 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) .notLinkBattle call SaveScreenTilesToBuffer2 ld a, [W_BATTLETYPE] - cp $2 ; is it a safari battle? + cp BATTLE_TYPE_SAFARI jr nz, BagWasSelected ; bait was selected @@ -2333,7 +2333,7 @@ UseBagItem: xor a ld [wCurrentMenuItem], a ld a, [W_BATTLETYPE] - cp $2 ; is it a safari battle? + cp BATTLE_TYPE_SAFARI jr z, .checkIfMonCaptured ld a, [wActionResultOrTookBattleTurn] @@ -2355,7 +2355,7 @@ UseBagItem: jr nz, .returnAfterCapturingMon ld a, [W_BATTLETYPE] - cp $2 ; is it a safari battle? + cp BATTLE_TYPE_SAFARI jr z, .returnAfterUsingItem_NoCapture ; not a safari battle call LoadScreenTilesFromBuffer1 @@ -2386,7 +2386,7 @@ PartyMenuOrRockOrRun: ; party menu or rock was selected call SaveScreenTilesToBuffer2 ld a, [W_BATTLETYPE] - cp $2 ; is it a safari battle? + cp BATTLE_TYPE_SAFARI jr nz, .partyMenuWasSelected ; safari battle ld a, SAFARI_ROCK diff --git a/engine/battle/init_battle_variables.asm b/engine/battle/init_battle_variables.asm index 6a4cd771..5791730c 100644 --- a/engine/battle/init_battle_variables.asm +++ b/engine/battle/init_battle_variables.asm @@ -32,7 +32,7 @@ InitBattleVariables: ; 525af (14:65af) jr c, .notSafariBattle cp SAFARI_ZONE_REST_HOUSE_1 jr nc, .notSafariBattle - ld a, $2 ; safari battle + ld a, BATTLE_TYPE_SAFARI ld [W_BATTLETYPE], a .notSafariBattle jpab PlayBattleMusic diff --git a/engine/hidden_object_functions17.asm b/engine/hidden_object_functions17.asm index 77f3eeb9..65a4669e 100755 --- a/engine/hidden_object_functions17.asm +++ b/engine/hidden_object_functions17.asm @@ -95,23 +95,23 @@ LinkCableHelp: ; 5dc29 (17:5c29) ld hl, LinkCableHelpText1 call PrintText xor a - ld [W_ANIMATIONID], a + ld [wMenuItemOffset], a ; not used ld [wCurrentMenuItem], a ld [wLastMenuItem], a ld a, A_BUTTON | B_BUTTON ld [wMenuWatchedKeys], a - ld a, $3 + ld a, 3 ld [wMaxMenuItem], a - ld a, $2 + ld a, 2 ld [wTopMenuItemY], a - ld a, $1 + ld a, 1 ld [wTopMenuItemX], a .linkHelpLoop ld hl, wd730 set 6, [hl] coord hl, 0, 0 - ld b, $8 - ld c, $d + ld b, 8 + ld c, 13 call TextBoxBorder coord hl, 2, 2 ld de, HowToLinkText @@ -122,13 +122,13 @@ LinkCableHelp: ; 5dc29 (17:5c29) bit 1, a ; pressed b jr nz, .exit ld a, [wCurrentMenuItem] - cp $3 ; pressed a on "STOP READING" + cp 3 ; pressed a on "STOP READING" jr z, .exit ld hl, wd730 res 6, [hl] ld hl, LinkCableInfoTexts add a - ld d, $0 + ld d, 0 ld e, a add hl, de ld a, [hli] @@ -179,16 +179,16 @@ ViridianSchoolBlackboard: ; 5dced (17:5ced) ld hl, ViridianSchoolBlackboardText1 call PrintText xor a - ld [W_ANIMATIONID], a + ld [wMenuItemOffset], a ld [wCurrentMenuItem], a ld [wLastMenuItem], a ld a, D_LEFT | D_RIGHT | A_BUTTON | B_BUTTON ld [wMenuWatchedKeys], a - ld a, $2 + ld a, 2 ld [wMaxMenuItem], a - ld a, $2 + ld a, 2 ld [wTopMenuItemY], a - ld a, $1 + ld a, 1 ld [wTopMenuItemX], a .blackboardLoop ld hl, wd730 @@ -210,34 +210,34 @@ ViridianSchoolBlackboard: ; 5dced (17:5ced) bit 4, a ; pressed right jr z, .didNotPressRight ; move cursor to right column - ld a, $2 + ld a, 2 ld [wMaxMenuItem], a - ld a, $2 + ld a, 2 ld [wTopMenuItemY], a - ld a, $6 + ld a, 6 ld [wTopMenuItemX], a - ld a, $3 - ld [W_ANIMATIONID], a + ld a, 3 ; in the the right column, use an offset to prevent overlap + ld [wMenuItemOffset], a jr .blackboardLoop .didNotPressRight bit 5, a ; pressed left jr z, .didNotPressLeftOrRight ; move cursor to left column - ld a, $2 + ld a, 2 ld [wMaxMenuItem], a - ld a, $2 + ld a, 2 ld [wTopMenuItemY], a - ld a, $1 + ld a, 1 ld [wTopMenuItemX], a xor a - ld [W_ANIMATIONID], a + ld [wMenuItemOffset], a jr .blackboardLoop .didNotPressLeftOrRight ld a, [wCurrentMenuItem] ld b, a - ld a, [W_ANIMATIONID] + ld a, [wMenuItemOffset] add b - cp $5 ; cursor is pointing to "QUIT" + cp 5 ; cursor is pointing to "QUIT" jr z, .exitBlackboard ; we must have pressed a on a status condition ; so print the text @@ -245,7 +245,7 @@ ViridianSchoolBlackboard: ; 5dced (17:5ced) res 6, [hl] ld hl, ViridianBlackboardStatusPointers add a - ld d, $0 + ld d, 0 ld e, a add hl, de ld a, [hli] diff --git a/engine/hidden_object_functions7.asm b/engine/hidden_object_functions7.asm index 02d3928a..0c1e2be2 100755 --- a/engine/hidden_object_functions7.asm +++ b/engine/hidden_object_functions7.asm @@ -147,7 +147,7 @@ CinnabarGymQuiz: ; 1ea25 (7:6a25) ld h, [hl] ld l, a call PrintText - ld a, $1 + ld a, 1 ld [wDoNotWaitForButtonPressAfterDisplayingText], a call CinnabarGymQuiz_1ea92 jp TextScriptEnd @@ -391,23 +391,23 @@ BillsHousePokemonList: ; 1ec05 (7:6c05) ld hl, BillsHousePokemonListText1 call PrintText xor a - ld [W_ANIMATIONID], a + ld [wMenuItemOffset], a ; not used ld [wCurrentMenuItem], a ld [wLastMenuItem], a ld a, A_BUTTON | B_BUTTON ld [wMenuWatchedKeys], a - ld a, $4 + ld a, 4 ld [wMaxMenuItem], a - ld a, $2 + ld a, 2 ld [wTopMenuItemY], a - ld a, $1 + ld a, 1 ld [wTopMenuItemX], a .billsPokemonLoop ld hl, wd730 set 6, [hl] coord hl, 0, 0 - ld b, $a - ld c, $9 + ld b, 10 + ld c, 9 call TextBoxBorder coord hl, 2, 2 ld de, BillsMonListText diff --git a/engine/items/items.asm b/engine/items/items.asm index f0666587..1d2001f0 100755 --- a/engine/items/items.asm +++ b/engine/items/items.asm @@ -101,97 +101,143 @@ ItemUsePtrTable: ; d5e1 (3:55e1) dw ItemUsePPRestore ; MAX_ELIXER ItemUseBall: ; d687 (3:5687) + +; Balls can't be used out of battle. ld a,[W_ISINBATTLE] and a - jp z,ItemUseNotTime ; not in battle + jp z,ItemUseNotTime + +; Balls can't catch trainers' Pokémon. dec a jp nz,ThrowBallAtTrainerMon + +; If this is for the old man battle, skip checking if the party & box are full. ld a,[W_BATTLETYPE] dec a - jr z,.UseBall - ld a,[wPartyCount] ;is Party full? + jr z,.canUseBall + + ld a,[wPartyCount] ; is party full? cp a,PARTY_LENGTH - jr nz,.UseBall - ld a,[W_NUMINBOX] ;is Box full? + jr nz,.canUseBall + ld a,[W_NUMINBOX] ; is box full? cp a,MONS_PER_BOX jp z,BoxFullCannotThrowBall -.UseBall -;ok, you can use a ball + +.canUseBall xor a ld [wCapturedMonSpecies],a + ld a,[W_BATTLETYPE] - cp a,2 ;SafariBattle + cp a,BATTLE_TYPE_SAFARI jr nz,.skipSafariZoneCode + .safariZone - ; remove a Safari Ball from inventory ld hl,W_NUMSAFARIBALLS - dec [hl] + dec [hl] ; remove a Safari Ball + .skipSafariZoneCode call RunDefaultPaletteCommand - ld a,$43 - ld [wd11e],a - call LoadScreenTilesFromBuffer1 ;restore screenBuffer from Backup + + ld a,$43 ; successful capture value + ld [wPokeBallAnimData],a + + call LoadScreenTilesFromBuffer1 ld hl,ItemUseText00 call PrintText + +; If the player is fighting an unidentified ghost, set the value that indicates +; the Pokémon can't be caught and skip the capture calculations. callab IsGhostBattle - ld b,$10 - jp z,.next12 + ld b,$10 ; can't be caught value + jp z,.setAnimData + ld a,[W_BATTLETYPE] dec a jr nz,.notOldManBattle + .oldManBattle ld hl,W_GRASSRATE ld de,wPlayerName ld bc,NAME_LENGTH - call CopyData ; save the player's name in the Wild Monster data (part of the Cinnabar Island Missingno glitch) - jp .BallSuccess + call CopyData ; save the player's name in the Wild Monster data (part of the Cinnabar Island Missingno. glitch) + jp .captured + .notOldManBattle +; If the player is fighting the ghost Marowak, set the value that indicates the +; Pokémon can't be caught and skip the capture calculations. ld a,[W_CURMAP] cp a,POKEMONTOWER_6 jr nz,.loop ld a,[wEnemyMonSpecies2] cp a,MAROWAK - ld b,$10 - jp z,.next12 -; if not fighting ghost Marowak, loop until a random number in the current -; pokeball's allowed range is found + ld b,$10 ; can't be caught value + jp z,.setAnimData + +; Get the first random number. Let it be called Rand1. +; Rand1 must be within a certain range according the kind of ball being thrown. +; The ranges are as follows. +; Poké Ball: [0, 255] +; Great Ball: [0, 200] +; Ultra/Safari Ball: [0, 150] +; Loop until an acceptable number is found. + .loop call Random ld b,a + +; Get the item ID. ld hl,wcf91 ld a,[hl] + +; The Master Ball always succeeds. cp a,MASTER_BALL - jp z,.BallSuccess + jp z,.captured + +; Anything will do for the basic Poké Ball. cp a,POKE_BALL jr z,.checkForAilments + +; If it's a Great/Ultra/Safari Ball and Rand1 is greater than 200, try again. ld a,200 cp b - jr c,.loop ;get only numbers <= 200 for Great Ball + jr c,.loop + +; Less than or equal to 200 is good enough for a Great Ball. ld a,[hl] cp a,GREAT_BALL jr z,.checkForAilments - ld a,150 ;get only numbers <= 150 for Ultra Ball + +; If it's an Ultra/Safari Ball and Rand1 is greater than 150, try again. + ld a,150 cp b jr c,.loop + .checkForAilments -; pokemon can be caught more easily with any (primary) status ailment -; Frozen/Asleep pokemon are relatively even easier to catch -; for Frozen/Asleep pokemon, any random number from 0-24 ensures a catch. -; for the others, a random number from 0-11 ensures a catch. - ld a,[wEnemyMonStatus] ;status ailments +; Pokémon can be caught more easily with a status ailment. +; Depending on the status ailment, a certain value will be subtracted from +; Rand1. Let this value be called Status. +; The larger Status is, the more easily the Pokémon can be caught. +; no status ailment: Status = 0 +; Burn/Paralysis/Poison: Status = 12 +; Freeze/Sleep: Status = 25 +; If Status is greater than Rand1, the Pokémon will be caught for sure. + ld a,[wEnemyMonStatus] and a - jr z,.noAilments - and a, 1 << FRZ | SLP ;is frozen and/or asleep? + jr z,.skipAilmentValueSubtraction ; no ailments + and a, 1 << FRZ | SLP ld c,12 jr z,.notFrozenOrAsleep ld c,25 .notFrozenOrAsleep ld a,b sub c - jp c,.BallSuccess + jp c,.captured ld b,a -.noAilments - push bc ;save RANDOM number + +.skipAilmentValueSubtraction + push bc ; save (Rand1 - Status) + +; Calculate MaxHP * 255. xor a ld [H_MULTIPLICAND],a ld hl,wEnemyMonMaxHP @@ -201,121 +247,178 @@ ItemUseBall: ; d687 (3:5687) ld [H_MULTIPLICAND + 2],a ld a,255 ld [H_MULTIPLIER],a - call Multiply ; MaxHP * 255 + call Multiply + +; Determine BallFactor. It's 8 for Great Balls and 12 for the others. ld a,[wcf91] cp a,GREAT_BALL - ld a,12 ;any other BallFactor - jr nz,.next7 + ld a,12 + jr nz,.skip1 ld a,8 -.next7 + +.skip1 +; Note that the results of all division operations are floored. + +; Calculate (MaxHP * 255) / BallFactor. ld [H_DIVISOR],a - ld b,4 ; number of bytes in dividend + ld b,4 ; number of bytes in dividend call Divide + +; Divide the enemy's current HP by 4. HP is not supposed to exceed 999 so +; the result should fit in a. If the division results in a quotient of 0, +; change it to 1. ld hl,wEnemyMonHP ld a,[hli] ld b,a ld a,[hl] - -; explanation: we have a 16-bit value equal to [b << 8 | a]. -; This number is divided by 4. The result is 8 bit (reg. a). -; Always bigger than zero. srl b rr a srl b - rr a ; a = current HP / 4 + rr a and a - jr nz,.next8 + jr nz,.skip2 inc a -.next8 + +.skip2 +; Let W = ((MaxHP * 255) / BallFactor) / max(HP / 4, 1). Calculate W. ld [H_DIVISOR],a ld b,4 - call Divide ; ((MaxHP * 255) / BallFactor) / (CurHP / 4) + call Divide + +; If W > 255, store 255 in [H_QUOTIENT + 3]. +; Let X = min(W, 255) = [H_QUOTIENT + 3]. ld a,[H_QUOTIENT + 2] and a - jr z,.next9 + jr z,.skip3 ld a,255 ld [H_QUOTIENT + 3],a -.next9 - pop bc - ld a,[wEnemyMonCatchRate] ;enemy: Catch Rate + +.skip3 + pop bc ; b = Rand1 - Status + +; If Rand1 - Status > CatchRate, the ball fails to capture the Pokémon. + ld a,[wEnemyMonCatchRate] cp b - jr c,.next10 + jr c,.failedToCapture + +; If W > 255, the ball captures the Pokémon. ld a,[H_QUOTIENT + 2] and a - jr nz,.BallSuccess ; if ((MaxHP * 255) / BallFactor) / (CurHP / 4) > 0x255, automatic success - call Random + jr nz,.captured + + call Random ; Let this random number be called Rand2. + +; If Rand2 > X, the ball fails to capture the Pokémon. ld b,a ld a,[H_QUOTIENT + 3] cp b - jr c,.next10 -.BallSuccess - jr .BallSuccess2 -.next10 + jr c,.failedToCapture + +.captured + jr .skipShakeCalculations + +.failedToCapture ld a,[H_QUOTIENT + 3] - ld [wd11e],a + ld [wPokeBallCaptureCalcTemp],a ; Save X. + +; Calculate CatchRate * 100. xor a ld [H_MULTIPLICAND],a ld [H_MULTIPLICAND + 1],a - ld a,[wEnemyMonCatchRate] ;enemy: Catch Rate + ld a,[wEnemyMonCatchRate] ld [H_MULTIPLICAND + 2],a ld a,100 ld [H_MULTIPLIER],a - call Multiply ; CatchRate * 100 + call Multiply + +; Determine BallFactor2. +; Poké Ball: BallFactor2 = 255 +; Great Ball: BallFactor2 = 200 +; Ultra/Safari Ball: BallFactor2 = 150 ld a,[wcf91] ld b,255 cp a,POKE_BALL - jr z,.next11 + jr z,.skip4 ld b,200 cp a,GREAT_BALL - jr z,.next11 + jr z,.skip4 ld b,150 cp a,ULTRA_BALL - jr z,.next11 -.next11 + jr z,.skip4 + +.skip4 +; Let Y = (CatchRate * 100) / BallFactor2. Calculate Y. ld a,b ld [H_DIVISOR],a ld b,4 call Divide + +; If Y > 255, there are 3 shakes. +; Note that this shouldn't be possible. +; The maximum value of Y is (255 * 100) / 150 = 170. ld a,[H_QUOTIENT + 2] and a - ld b,$63 - jr nz,.next12 - ld a,[wd11e] + ld b,$63 ; 3 shakes + jr nz,.setAnimData + +; Calculate X * Y. + ld a,[wPokeBallCaptureCalcTemp] ld [H_MULTIPLIER],a call Multiply + +; Calculate (X * Y) / 255. ld a,255 ld [H_DIVISOR],a ld b,4 call Divide - ld a,[wEnemyMonStatus] ;status ailments + +; Determine Status2. +; no status ailment: Status2 = 0 +; Burn/Paralysis/Poison: Status2 = 5 +; Freeze/Sleep: Status2 = 10 + ld a,[wEnemyMonStatus] and a - jr z,.next13 + jr z,.skip5 and a, 1 << FRZ | SLP ld b,5 - jr z,.next14 + jr z,.addAilmentValue ld b,10 -.next14 + +.addAilmentValue +; If the Pokémon has a status ailment, add Status2. ld a,[H_QUOTIENT + 3] add b ld [H_QUOTIENT + 3],a -.next13 + +.skip5 +; Finally determine the number of shakes. +; Let Z = ((X * Y) / 255) + Status2 = [H_QUOTIENT + 3]. +; The number of shakes depend on the range Z is in. +; 0 ≤ Z < 10: 0 shakes (the ball misses) +; 10 ≤ Z < 30: 1 shake +; 30 ≤ Z < 70: 2 shakes +; 70 ≤ Z: 3 shakes ld a,[H_QUOTIENT + 3] cp a,10 ld b,$20 - jr c,.next12 + jr c,.setAnimData cp a,30 ld b,$61 - jr c,.next12 + jr c,.setAnimData cp a,70 ld b,$62 - jr c,.next12 + jr c,.setAnimData ld b,$63 -.next12 + +.setAnimData ld a,b ld [wPokeBallAnimData],a -.BallSuccess2 + +.skipShakeCalculations ld c,20 call DelayFrames + +; Do the animation. ld a,TOSS_ANIM ld [W_ANIMATIONID],a xor a @@ -331,45 +434,61 @@ ItemUseBall: ; d687 (3:5687) ld [wcf91],a pop af ld [wWhichPokemon],a + +; Determine the message to display from the animation. ld a,[wPokeBallAnimData] cp a,$10 ld hl,ItemUseBallText00 - jp z,.printText0 + jp z,.printMessage cp a,$20 ld hl,ItemUseBallText01 - jp z,.printText0 + jp z,.printMessage cp a,$61 ld hl,ItemUseBallText02 - jp z,.printText0 + jp z,.printMessage cp a,$62 ld hl,ItemUseBallText03 - jp z,.printText0 + jp z,.printMessage cp a,$63 ld hl,ItemUseBallText04 - jp z,.printText0 - ld hl,wEnemyMonHP ;current HP + jp z,.printMessage + +; Save current HP. + ld hl,wEnemyMonHP ld a,[hli] push af ld a,[hli] - push af ;backup currentHP... + push af + +; Save status ailment. inc hl ld a,[hl] - push af ;...and status ailments + push af + push hl + +; If the Pokémon is transformed, the Pokémon is assumed to be a Ditto. +; This is a bug because a wild Pokémon could have used Transform via +; Mirror Move even though the only wild Pokémon that knows Transform is Ditto. ld hl,W_ENEMYBATTSTATUS3 bit Transformed,[hl] - jr z,.next15 - ld a,$4c + jr z,.notTransformed + ld a,DITTO ld [wEnemyMonSpecies2],a - jr .next16 -.next15 + jr .skip6 + +.notTransformed +; If the Pokémon is not transformed, set the transformed bit and copy the +; DVs to wTransformedEnemyMonOriginalDVs so that LoadEnemyMonData won't generate +; new DVs. set Transformed,[hl] ld hl,wTransformedEnemyMonOriginalDVs ld a,[wEnemyMonDVs] ld [hli],a ld a,[wEnemyMonDVs + 1] ld [hl],a -.next16 + +.skip6 ld a,[wcf91] push af ld a,[wEnemyMonSpecies2] @@ -387,15 +506,18 @@ ItemUseBall: ; d687 (3:5687) ld [hld],a pop af ld [hl],a - ld a,[wEnemyMonSpecies] ;enemy + ld a,[wEnemyMonSpecies] ld [wCapturedMonSpecies],a ld [wcf91],a ld [wd11e],a ld a,[W_BATTLETYPE] - dec a - jr z,.printText1 + dec a ; is this the old man battle? + jr z,.oldManCaughtMon ; if so, don't give the player the caught Pokémon + ld hl,ItemUseBallText05 call PrintText + +; Add the caught Pokémon to the Pokédex. predef IndexToPokedex ld a,[wd11e] dec a @@ -411,46 +533,56 @@ ItemUseBall: ; d687 (3:5687) ld b,FLAG_SET predef FlagActionPredef pop af - and a - jr nz,.checkParty + + and a ; was the Pokémon already in the Pokédex? + jr nz,.skipShowingPokedexData ; if so, don't show the Pokédex data + ld hl,ItemUseBallText06 call PrintText call ClearSprites - ld a,[wEnemyMonSpecies] ;caught mon_ID + ld a,[wEnemyMonSpecies] ld [wd11e],a predef ShowPokedexData -.checkParty + +.skipShowingPokedexData ld a,[wPartyCount] - cp a,PARTY_LENGTH ;is party full? + cp a,PARTY_LENGTH ; is party full? jr z,.sendToBox xor a ; PLAYER_PARTY_DATA ld [wMonDataLocation],a call ClearSprites - call AddPartyMon ;add mon to Party - jr .End + call AddPartyMon + jr .done + .sendToBox call ClearSprites call SendNewMonToBox ld hl,ItemUseBallText07 CheckEvent EVENT_MET_BILL - jr nz,.sendToBox2 + jr nz,.printTransferredToPCText ld hl,ItemUseBallText08 -.sendToBox2 +.printTransferredToPCText call PrintText - jr .End -.printText1 + jr .done + +.oldManCaughtMon ld hl,ItemUseBallText05 -.printText0 + +.printMessage call PrintText call ClearSprites -.End + +.done ld a,[W_BATTLETYPE] - and a - ret nz + and a ; is this the old man battle? + ret nz ; if so, don't remove a ball from the bag + +; Remove a ball from the bag. ld hl,wNumBagItems inc a ld [wItemQuantity],a jp RemoveItemFromInventory + ItemUseBallText00: ; d937 (3:5937) ;"It dodged the thrown ball!" ;"This pokemon can't be caught" @@ -769,10 +901,10 @@ ItemUseMedicine: ; dabb (3:5abb) ld hl,W_PLAYERBATTSTATUS3 res BadlyPoisoned,[hl] ; heal Toxic status pop hl - ld bc,30 + ld bc,wPartyMon1Stats - wPartyMon1Status add hl,bc ; hl now points to party stats - ld de,wBattleMonMaxHP - ld bc,10 + ld de,wBattleMonStats + ld bc,NUM_STATS * 2 call CopyData ; copy party stats to in-battle stat data predef DoubleOrHalveSelectedStats jp .doneHealing @@ -827,7 +959,7 @@ ItemUseMedicine: ; dabb (3:5abb) .compareCurrentHPToMaxHP push hl push bc - ld bc,32 + ld bc,wPartyMon1MaxHP - (wPartyMon1HP + 1) add hl,bc ; hl now points to max HP pop bc ld a,[hli] @@ -859,7 +991,7 @@ ItemUseMedicine: ; dabb (3:5abb) ld [wChannelSoundIDs + CH4],a push hl push de - ld bc,32 + ld bc,wPartyMon1MaxHP - (wPartyMon1HP + 1) add hl,bc ; hl now points to max HP ld a,[hli] ld [wHPBarMaxHP+1],a @@ -892,7 +1024,7 @@ ItemUseMedicine: ; dabb (3:5abb) ld [H_DIVISOR],a ld b,2 ; number of bytes call Divide ; get 1/5 of max HP of pokemon that used Softboiled - ld bc,wPartyMon1HP - wPartyMon1MaxHP + ld bc,(wPartyMon1HP + 1) - (wPartyMon1MaxHP + 1) add hl,bc ; hl now points to LSB of current HP of pokemon that used Softboiled ; subtract 1/5 of max HP from current HP of pokemon that used Softboiled ld a,[H_QUOTIENT + 3] @@ -971,7 +1103,7 @@ ItemUseMedicine: ; dabb (3:5abb) inc hl ld d,h ld e,l ; de now points to current HP - ld hl,33 + ld hl,(wPartyMon1MaxHP + 1) - (wPartyMon1HP + 1) add hl,de ; hl now points to max HP ld a,[wcf91] cp a,REVIVE @@ -1018,7 +1150,7 @@ ItemUseMedicine: ; dabb (3:5abb) ld a,[wcf91] cp a,FULL_RESTORE jr nz,.updateInBattleData - ld bc,-31 + ld bc,wPartyMon1Status - (wPartyMon1MaxHP + 1) add hl,bc xor a ld [hl],a ; remove the status ailment in the party data @@ -1041,7 +1173,7 @@ ItemUseMedicine: ; dabb (3:5abb) ld [wBattleMonStatus],a ; remove the status ailment in the in-battle pokemon data .calculateHPBarCoords ld hl,wOAMBuffer + $90 - ld bc,2 * 20 + ld bc,2 * SCREEN_WIDTH inc d .calculateHPBarCoordsLoop add hl,bc @@ -1121,7 +1253,7 @@ ItemUseMedicine: ; dabb (3:5abb) ld a,[hl] ld [wd0b5],a ld [wd11e],a - ld bc,33 + ld bc,wPartyMon1Level - wPartyMon1 add hl,bc ; hl now points to level ld a,[hl] ; a = level ld [W_CURENEMYLVL],a ; store level @@ -1138,7 +1270,7 @@ ItemUseMedicine: ; dabb (3:5abb) push hl sub a,HP_UP add a - ld bc,17 + ld bc,wPartyMon1HPExp - wPartyMon1 add hl,bc add l ld l,a @@ -1186,17 +1318,17 @@ ItemUseMedicine: ; dabb (3:5abb) call PrintText jp GBPalWhiteOut .recalculateStats - ld bc,34 + ld bc,wPartyMon1Stats - wPartyMon1 add hl,bc ld d,h ld e,l ; de now points to stats - ld bc,-18 - add hl,bc ; hl now points to byte 3 of experience + ld bc,(wPartyMon1Exp + 2) - wPartyMon1Stats + add hl,bc ; hl now points to LSB of experience ld b,1 jp CalcStats ; recalculate stats .useRareCandy push hl - ld bc,33 + ld bc,wPartyMon1Level - wPartyMon1 add hl,bc ; hl now points to level ld a,[hl] ; a = level cp a, MAX_LEVEL @@ -1210,8 +1342,8 @@ ItemUseMedicine: ; dabb (3:5abb) callab CalcExperience ; calculate experience for next level and store it at $ff96 pop de pop hl - ld bc,-19 - add hl,bc ; hl now points to experience + ld bc,wPartyMon1Exp - wPartyMon1Level + add hl,bc ; hl now points to MSB of experience ; update experience to minimum for new level ld a,[hExperience] ld [hli],a @@ -1226,7 +1358,7 @@ ItemUseMedicine: ; dabb (3:5abb) push af push de push hl - ld bc,34 + ld bc,wPartyMon1MaxHP - wPartyMon1 add hl,bc ; hl now points to MSB of max HP ld a,[hli] ld b,a @@ -1236,8 +1368,8 @@ ItemUseMedicine: ; dabb (3:5abb) push hl call .recalculateStats pop hl - ld bc,35 ; hl now points to LSB of max HP - add hl,bc + ld bc,(wPartyMon1MaxHP + 1) - wPartyMon1 + add hl,bc ; hl now points to LSB of max HP pop bc ld a,[hld] sub c @@ -1246,8 +1378,8 @@ ItemUseMedicine: ; dabb (3:5abb) sbc b ld b,a ; bc = the amount of max HP gained from leveling up ; add the amount gained to the current HP - ld de,-32 - add hl,de ; hl now points to MSB of current HP + ld de,(wPartyMon1HP + 1) - wPartyMon1MaxHP + add hl,de ; hl now points to LSB of current HP ld a,[hl] add c ld [hld],a @@ -1421,7 +1553,7 @@ ItemUseCardKey: ; e022 (3:6022) xor a ld [wUnusedD71F],a call GetTileAndCoordsInFrontOfPlayer - ld a,[GetTileAndCoordsInFrontOfPlayer] ; $4586 + ld a,[GetTileAndCoordsInFrontOfPlayer] cp a,$18 jr nz,.next0 ld hl,CardKeyTable1 diff --git a/engine/menu/main_menu.asm b/engine/menu/main_menu.asm index 6c109cec..78830093 100755 --- a/engine/menu/main_menu.asm +++ b/engine/menu/main_menu.asm @@ -20,7 +20,7 @@ MainMenu: ; 5af2 (1:5af2) ld [hli],a ld [hli],a ld [hl],a - ld [W_ANIMATIONID],a + ld [wDefaultMap],a ld hl,wd72e res 6,[hl] call ClearScreen @@ -269,7 +269,7 @@ LinkMenu: ; 5c0a (1:5c0a) call DelayFrames ld hl, wd732 res 1, [hl] - ld a, [W_ANIMATIONID] + ld a, [wDefaultMap] ld [wDestinationMap], a call SpecialWarpIn ld c, 20 diff --git a/engine/menu/naming_screen.asm b/engine/menu/naming_screen.asm index 978216c8..703d570a 100755 --- a/engine/menu/naming_screen.asm +++ b/engine/menu/naming_screen.asm @@ -166,7 +166,7 @@ DisplayNamingScreen: ; 6596 (1:6596) call RunDefaultPaletteCommand call GBPalNormal xor a - ld [W_SUBANIMTRANSFORM], a + ld [wAnimCounter], a ld hl, wd730 res 6, [hl] ld a, [W_ISINBATTLE] diff --git a/engine/menu/start_sub_menus.asm b/engine/menu/start_sub_menus.asm index ab8c8756..678877ef 100755 --- a/engine/menu/start_sub_menus.asm +++ b/engine/menu/start_sub_menus.asm @@ -160,7 +160,7 @@ StartMenu_Pokemon: ; 130a9 (4:70a9) .surf bit 4,a ; does the player have the Soul Badge? jp z,.newBadgeRequired - callba CheckForForcedBikeSurf + callba IsSurfingAllowed ld hl,wd728 bit 1,[hl] res 1,[hl] diff --git a/engine/oak_speech.asm b/engine/oak_speech.asm index 0de7ffad..48e8da80 100755 --- a/engine/oak_speech.asm +++ b/engine/oak_speech.asm @@ -48,7 +48,7 @@ OakSpeech: ; 6115 (1:6115) ld a,1 ld [wItemQuantity],a call AddItemToInventory ; give one potion - ld a,[W_ANIMATIONID] + ld a,[wDefaultMap] ld [wDestinationMap],a call SpecialWarpIn xor a diff --git a/engine/overworld/movement.asm b/engine/overworld/movement.asm index be10fd69..2ed49838 100644 --- a/engine/overworld/movement.asm +++ b/engine/overworld/movement.asm @@ -133,8 +133,8 @@ UpdateNPCSprite: ; 4ed1 (1:4ed1) ld l, a inc l ld a, [hl] ; c1x1 - bit 7, a - jp nz, InitializeSpriteFacingDirection ; c1x1 >= $80 + bit 7, a ; is the face player flag set? + jp nz, MakeNPCFacePlayer ld b, a ld a, [wFontLoaded] bit 0, a @@ -400,10 +400,15 @@ notYetMoving: ; 5073 (1:5073) ld [hl], $0 ; c1x8 = 0 (walk animation frame) jp UpdateSpriteImage -InitializeSpriteFacingDirection: ; 507f (1:507f) +MakeNPCFacePlayer: ; 507f (1:507f) +; Make an NPC face the player if the player has spoken to him or her. + +; Check if the behaviour of the NPC facing the player when spoken to is +; disabled. This is only done when rubbing the S.S. Anne captain's back. ld a, [wd72d] bit 5, a jr nz, notYetMoving + res 7, [hl] ld a, [wPlayerDirection] bit PLAYER_DIR_BIT_UP, a diff --git a/engine/town_map.asm b/engine/town_map.asm index 225de2b8..8bf11358 100755 --- a/engine/town_map.asm +++ b/engine/town_map.asm @@ -444,8 +444,12 @@ WritePlayerOrBirdSpriteOAM: ; 7126d (1c:526d) WriteTownMapSpriteOAM: ; 71279 (1c:5279) push hl + +; Subtract 4 from c (X coord) and 4 from b (Y coord). However, the carry from c +; is added to b, so the net result is that only 3 is subtracted from b. lb hl, -4, -4 - add hl, bc ; subtract 4 from c (X coord) and 4 from b (Y coord) + add hl, bc + ld b, h ld c, l pop hl @@ -469,14 +473,14 @@ WriteAsymmetricMonPartySpriteOAM: ; 71281 (1c:5281) xor a ld [hli], a inc d - ld a, $8 + ld a, 8 add c ld c, a dec e jr nz, .innerLoop pop bc pop de - ld a, $8 + ld a, 8 add b ld b, a dec d @@ -3167,7 +3167,7 @@ SaveScreenTilesToBuffer2:: ; 36f4 (0:36f4) LoadScreenTilesFromBuffer2:: ; 3701 (0:3701) call LoadScreenTilesFromBuffer2DisableBGTransfer - ld a, $1 + ld a, 1 ld [H_AUTOBGTRANSFERENABLED], a ret @@ -3177,7 +3177,7 @@ LoadScreenTilesFromBuffer2DisableBGTransfer:: ; 3709 (0:3709) ld [H_AUTOBGTRANSFERENABLED], a ld hl, wTileMapBackup2 coord de, 0, 0 - ld bc, $168 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT call CopyData ret @@ -3194,7 +3194,7 @@ LoadScreenTilesFromBuffer1:: ; 3725 (0:3725) coord de, 0, 0 ld bc, SCREEN_WIDTH * SCREEN_HEIGHT call CopyData - ld a, $1 + ld a, 1 ld [H_AUTOBGTRANSFERENABLED], a ret diff --git a/home/overworld.asm b/home/overworld.asm index 051d055e..9eafba04 100644 --- a/home/overworld.asm +++ b/home/overworld.asm @@ -1190,8 +1190,8 @@ IsSpriteInFrontOfPlayer2:: ; 0b6d (0:0b6d) ld a,l and a,$f0 inc a - ld l,a - set 7,[hl] + ld l,a ; hl = $c1x1 + set 7,[hl] ; set flag to make the sprite face the player ld a,e ld [hSpriteIndexOrTextID],a ret @@ -548,7 +548,7 @@ TestBattle: ld [W_OBTAINEDBADGES], a ld hl, W_FLAGS_D733 - set 0, [hl] + set BIT_TEST_BATTLE, [hl] ; Reset the party. ld hl, wPartyCount @@ -668,7 +668,7 @@ LoadSpecialWarpData: ; 62ff (1:62ff) xor a jr .done .notFirstMap - ld a, [wLastMap] + ld a, [wLastMap] ; this value is overwritten before it's ever read ld hl, wd732 bit 4, [hl] ; used dungeon warp (jumped down hole/waterfall)? jr nz, .usedDunegonWarp @@ -2751,12 +2751,15 @@ CanMoveBouldersText: ; cdbb (3:4dbb) TX_FAR _CanMoveBouldersText db "@" -CheckForForcedBikeSurf: ; cdc0 (3:4dc0) +IsSurfingAllowed: ; cdc0 (3:4dc0) +; Returns whether surfing is allowed in bit 1 of wd728. +; Surfing isn't allowed on the Cycling Road or in the lowest level of the +; Seafoam Islands before the current has been slowed with boulders. ld hl, wd728 set 1, [hl] ld a, [wd732] bit 5, a - jr nz, .asm_cdec + jr nz, .forcedToRideBike ld a, [W_CURMAP] cp SEAFOAM_ISLANDS_5 ret nz @@ -2769,7 +2772,7 @@ CheckForForcedBikeSurf: ; cdc0 (3:4dc0) res 1, [hl] ld hl, CurrentTooFastText jp PrintText -.asm_cdec +.forcedToRideBike ld hl, wd728 res 1, [hl] ld hl, CyclingIsFunText @@ -2799,7 +2802,7 @@ AddItemToInventory_: ; ce04 (3:4e04) push de push hl push hl - ld d,50 ; PC box can hold 50 items + ld d,PC_ITEM_CAPACITY ; how many items the PC can hold ld a,wNumBagItems & $FF cp l jr nz,.checkIfInventoryFull @@ -2807,7 +2810,7 @@ AddItemToInventory_: ; ce04 (3:4e04) cp h jr nz,.checkIfInventoryFull ; if the destination is the bag - ld d,20 ; bag can hold 20 items + ld d,BAG_ITEM_CAPACITY ; how many items the bag can hold .checkIfInventoryFull ld a,[hl] sub d diff --git a/scripts/halloffameroom.asm b/scripts/halloffameroom.asm index 1da6d3f5..de3cd779 100755 --- a/scripts/halloffameroom.asm +++ b/scripts/halloffameroom.asm @@ -47,11 +47,11 @@ HallofFameRoomScript2: ; 5a4bb (16:64bb) ld [wLastBlackoutMap], a callba SaveSAVtoSRAM ld b, 5 -.asm_5a4ff +.delayLoop ld c, 600 / 5 call DelayFrames dec b - jr nz, .asm_5a4ff + jr nz, .delayLoop call WaitForTextScrollButtonPress jp Init diff --git a/scripts/viridiancity.asm b/scripts/viridiancity.asm index 79ad444f..ae0b6212 100755 --- a/scripts/viridiancity.asm +++ b/scripts/viridiancity.asm @@ -71,7 +71,7 @@ ViridianCityScript1: ; 19062 (6:5062) ld [wListScrollOffset], a ; set up battle for Old Man - ld a, $1 + ld a, BATTLE_TYPE_OLD_MAN ld [W_BATTLETYPE], a ld a, 5 ld [W_CURENEMYLVL], a @@ -50,6 +50,7 @@ battle_struct: MACRO \1Moves:: ds NUM_MOVES \1DVs:: ds 2 \1Level:: db +\1Stats:: \1MaxHP:: dw \1Attack:: dw \1Defense:: dw @@ -1746,6 +1747,11 @@ wObjectToShow:: ; d07a ds 1 +wDefaultMap:: ; d07c +; the map you will start at when the debug bit is set + +wMenuItemOffset:: ; d07c + W_ANIMATIONID:: ; d07c ; ID number of the current battle animation ds 1 @@ -1789,7 +1795,7 @@ W_SUBANIMCOUNTER:: ; d087 ; counts the number of subentries left in the current subanimation ds 1 -wSaveFileStatus:: +wSaveFileStatus:: ; d088 ; 1 = no save file or save file is corrupted ; 2 = save file exists and no corruption has been detected ds 1 @@ -2068,6 +2074,8 @@ wFirstMonsNotOutYet:: ; d11d ; which will be the first mon sent out. ds 1 +wPokeBallCaptureCalcTemp:: ; d11e + ; lower nybble: number of shakes ; upper nybble: number of animations to play wPokeBallAnimData:: ; d11e @@ -2277,7 +2285,7 @@ wNumBagItems:: ; d31d ds 1 wBagItems:: ; d31e ; item, quantity - ds 20 * 2 + ds BAG_ITEM_CAPACITY * 2 ds 1 ; end wPlayerMoney:: ; d347 @@ -2590,7 +2598,7 @@ wNumBoxItems:: ; d53a ds 1 wBoxItems:: ; d53b ; item, quantity - ds 50 * 2 + ds PC_ITEM_CAPACITY * 2 ds 1 ; end wCurrentBoxNum:: ; d5a0 @@ -2921,8 +2929,14 @@ wUnusedD71F:: ; d71f ds 8 -wd728:: +wd728:: ; d728 ; bit 0: using Strength outside of battle +; bit 1: set by IsSurfingAllowed when surfing's allowed, but the caller resets it after checking the result +; bit 3: received Old Rod +; bit 4: received Good Rod +; bit 5: received Super Rod +; bit 6: gave one of the Saffron guards a drink +; bit 7: set by ItemUseCardKey, which is leftover code from a previous implementation of the Card Key ds 1 ds 1 @@ -2936,16 +2950,36 @@ wBeatGymFlags:: ; d72a wd72c:: ; d72c ; bit 0: if not set, the 3 minimum steps between random battles have passed +; bit 1: prevent audio fade out + ds 1 + +wd72d:: ; d72d +; This variable is used for temporary flags and as the destination map when +; warping to the Trade Center or Colosseum. +; bit 0: sprite facing directions have been initialised in the Trade Center +; bit 3: do scripted warp (used to warp back to Lavender Town from the top of the pokemon tower) +; bit 4: on a dungeon warp +; bit 5: don't make NPCs face the player when spoken to +; Bits 6 and 7 are set by scripts when starting major battles in the storyline, +; but they do not appear to affect anything. Bit 6 is reset after all battles +; and bit 7 is reset after trainer battles (but it's only set before trainer +; battles anyway). + ds 1 + +wd72e:: ; d72e +; bit 0: the player has received Lapras in the Silph Co. building +; bit 1: set in various places, but doesn't appear to have an effect +; bit 2: the player has healed pokemon at a pokemon center at least once +; bit 3: the player has a received a pokemon from Prof. Oak +; bit 4: disable battles +; bit 5: set when a battle ends and when the player blacks out in the overworld due to poison +; bit 6: using the link feature +; bit 7: set if scripted NPC movement has been initialised ds 1 -wd72d:: ds 1 ; misc temp flags? (in some scripts, bit 6 and 7 set after a special battle (e.g. gym leaders) has been won) - ; also used as a start menu flag - -wd72e:: -; bit 7: set if scripted NPC movement has been initialised - ds 2 ; more temp misc flags, used with npc movement, main menu and other stuff + ds 1 -wd730:: +wd730:: ; d730 ; bit 0: NPC sprite being moved by script ; bit 5: ignore joypad input ; bit 6: print text with no delay between each letter @@ -2970,6 +3004,9 @@ wd732:: ; d732 W_FLAGS_D733:: ; d733 ; bit 0: running a test battle +; bit 1: prevent music from changing when entering new map +; bit 2: skip the joypad check in CheckWarpsNoCollision (used for the forced warp down the waterfall in the Seafoam Islands) +; bit 3: trainer wants to battle ; bit 4: use variable [W_CURMAPSCRIPT] instead of the provided index for next frame's map script (used to start battle when talking to trainers) ; bit 7: used fly out of battle ds 1 |