diff options
Diffstat (limited to 'engine')
-rw-r--r-- | engine/add_party_mon.asm | 345 | ||||
-rw-r--r-- | engine/draw_badges.asm | 120 | ||||
-rw-r--r-- | engine/flag_action_predef.asm | 73 | ||||
-rw-r--r-- | engine/get_bag_item_quantity.asm | 18 | ||||
-rw-r--r-- | engine/heal_party.asm | 99 | ||||
-rw-r--r-- | engine/init_player_data.asm | 60 | ||||
-rw-r--r-- | engine/move_mon.asm | 172 | ||||
-rw-r--r-- | engine/overworld/boulders.asm | 94 | ||||
-rw-r--r-- | engine/overworld/check_player_state.asm | 236 | ||||
-rw-r--r-- | engine/overworld/clear_loadmapdata_vars.asm | 20 | ||||
-rw-r--r-- | engine/overworld/daycare_exp.asm | 18 | ||||
-rw-r--r-- | engine/overworld/get_coords_tile_in_front_of_player.asm | 87 | ||||
-rw-r--r-- | engine/overworld/load_tileset_header.asm | 51 | ||||
-rw-r--r-- | engine/overworld/load_wild_data.asm | 33 | ||||
-rw-r--r-- | engine/overworld/missable_objects.asm | 212 | ||||
-rw-r--r-- | engine/overworld/npc_pathfinding.asm | 201 | ||||
-rw-r--r-- | engine/overworld/print_safari_steps.asm | 36 | ||||
-rw-r--r-- | engine/overworld/replace_tile_block.asm | 126 | ||||
-rw-r--r-- | engine/overworld/step_functions.asm | 151 | ||||
-rw-r--r-- | engine/overworld/try_pushing_boulder.asm | 106 |
20 files changed, 2258 insertions, 0 deletions
diff --git a/engine/add_party_mon.asm b/engine/add_party_mon.asm new file mode 100644 index 00000000..b20913dd --- /dev/null +++ b/engine/add_party_mon.asm @@ -0,0 +1,345 @@ +_AddPartyMon: ; f161 (3:7161) +; 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 a, [wcf91] + cp KADABRA + jr nz, .skipGivingTwistedSpoon + ld a, $60 ; twistedspoon in gen 2 + ld [de], a +.skipGivingTwistedSpoon + 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: ; f2f9 (3:72f9) + call GetPredefRegisters + ; fallthrough +AddPartyMon_WriteMovePP: ; f2fc (3:72fc) + 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: ; f323 (3:7323) + 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
\ No newline at end of file diff --git a/engine/draw_badges.asm b/engine/draw_badges.asm new file mode 100644 index 00000000..bd4aeaa8 --- /dev/null +++ b/engine/draw_badges.asm @@ -0,0 +1,120 @@ +DrawBadges: ; e880 (3:6880) +; Draw 4x2 gym leader faces, with the faces replaced by +; badges if they are owned. Used in the player status screen. + +; In Japanese versions, names are displayed above faces. +; Instead of removing relevant code, the name graphics were erased. + +; Tile ids for face/badge graphics. + ld de, wBadgeOrFaceTiles + ld hl, .FaceBadgeTiles + ld bc, 8 + call CopyData + +; Booleans for each badge. + ld hl, wTempObtainedBadgesBooleans + ld bc, 8 + xor a + call FillMemory + +; Alter these based on owned badges. + ld de, wTempObtainedBadgesBooleans + ld hl, wBadgeOrFaceTiles + ld a, [wObtainedBadges] + ld b, a + ld c, 8 +.CheckBadge + srl b + jr nc, .NextBadge + ld a, [hl] + add 4 ; Badge graphics are after each face + ld [hl], a + ld a, 1 + ld [de], a +.NextBadge + inc hl + inc de + dec c + jr nz, .CheckBadge + +; Draw two rows of badges. + ld hl, wBadgeNumberTile + ld a, $d8 ; [1] + ld [hli], a + ld [hl], $60 ; First name + + coord hl, 2, 11 + ld de, wTempObtainedBadgesBooleans + call .DrawBadgeRow + + coord hl, 2, 14 + ld de, wTempObtainedBadgesBooleans + 4 +; call .DrawBadgeRow +; ret + +.DrawBadgeRow ; e8c9 (3:68c9) +; Draw 4 badges. + + ld c, 4 +.DrawBadge + push de + push hl + +; Badge no. + ld a, [wBadgeNumberTile] + ld [hli], a + inc a + ld [wBadgeNumberTile], a + +; Names aren't printed if the badge is owned. + ld a, [de] + and a + ld a, [wBadgeNameTile] + jr nz, .SkipName + call .PlaceTiles + jr .PlaceBadge + +.SkipName + inc a + inc a + inc hl + +.PlaceBadge + ld [wBadgeNameTile], a + ld de, SCREEN_WIDTH - 1 + add hl, de + ld a, [wBadgeOrFaceTiles] + call .PlaceTiles + add hl, de + call .PlaceTiles + +; Shift badge array back one byte. + push bc + ld hl, wBadgeOrFaceTiles + 1 + ld de, wBadgeOrFaceTiles + ld bc, 8 + call CopyData + pop bc + + pop hl + ld de, 4 + add hl, de + + pop de + inc de + dec c + jr nz, .DrawBadge + ret + +.PlaceTiles + ld [hli], a + inc a + ld [hl], a + inc a + ret + +.FaceBadgeTiles + db $20, $28, $30, $38, $40, $48, $50, $58 + +GymLeaderFaceAndBadgeTileGraphics: ; e91b (3:691b) + INCBIN "gfx/badges.2bpp"
\ No newline at end of file diff --git a/engine/flag_action_predef.asm b/engine/flag_action_predef.asm new file mode 100644 index 00000000..df38bb87 --- /dev/null +++ b/engine/flag_action_predef.asm @@ -0,0 +1,73 @@ +FlagActionPredef: ; f4ec (3:74ec) + call GetPredefRegisters + +FlagAction: ; f4ef (3:74ef) +; Perform action b on bit c +; in the bitfield at hl. +; 0: reset +; 1: set +; 2: read +; Return the result in c. + + push hl + push de + push bc + + ; bit + ld a, c + ld d, a + and 7 + ld e, a + + ; byte + ld a, d + srl a + srl a + srl a + add l + ld l, a + jr nc, .ok + inc h +.ok + + ; d = 1 << e (bitmask) + inc e + ld d, 1 +.shift + dec e + jr z, .shifted + sla d + jr .shift +.shifted + + ld a, b + and a + jr z, .reset + cp 2 + jr z, .read + +.set + ld b, [hl] + ld a, d + or b + ld [hl], a + jr .done + +.reset + ld b, [hl] + ld a, d + xor $ff + and b + ld [hl], a + jr .done + +.read + ld b, [hl] + ld a, d + and b +.done + pop bc + pop de + pop hl + ld c, a + ret
\ No newline at end of file diff --git a/engine/get_bag_item_quantity.asm b/engine/get_bag_item_quantity.asm new file mode 100644 index 00000000..2a462b5d --- /dev/null +++ b/engine/get_bag_item_quantity.asm @@ -0,0 +1,18 @@ +GetQuantityOfItemInBag: ; f735 (3:7735) +; In: b = item ID +; Out: b = how many of that item are in the bag + call GetPredefRegisters + ld hl, wNumBagItems +.loop + inc hl + ld a, [hli] + cp $ff + jr z, .notInBag + cp b + jr nz, .loop + ld a, [hl] + ld b, a + ret +.notInBag + ld b, 0 + ret
\ No newline at end of file diff --git a/engine/heal_party.asm b/engine/heal_party.asm new file mode 100644 index 00000000..4ef200a9 --- /dev/null +++ b/engine/heal_party.asm @@ -0,0 +1,99 @@ +HealParty: ; f52b (3:752b) +; Restore HP and PP. + + ld hl, wPartySpecies + ld de, wPartyMon1HP +.healmon + ld a, [hli] + cp $ff + jr z, .done + + push hl + push de + + ld hl, wPartyMon1Status - wPartyMon1HP + add hl, de + xor a + ld [hl], a + + push de + ld b, NUM_MOVES ; A Pokémon has 4 moves +.pp + ld hl, wPartyMon1Moves - wPartyMon1HP + add hl, de + + ld a, [hl] + and a + jr z, .nextmove + + dec a + ld hl, wPartyMon1PP - wPartyMon1HP + add hl, de + + push hl + push de + push bc + + ld hl, Moves + ld bc, MoveEnd - Moves + call AddNTimes + ld de, wcd6d + ld a, BANK(Moves) + call FarCopyData + ld a, [wcd6d + 5] ; PP is byte 5 of move data + + pop bc + pop de + pop hl + + inc de + push bc + ld b, a + ld a, [hl] + and $c0 + add b + ld [hl], a + pop bc + +.nextmove + dec b + jr nz, .pp + pop de + + ld hl, wPartyMon1MaxHP - wPartyMon1HP + add hl, de + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + + pop de + pop hl + + push hl + ld bc, wPartyMon2 - wPartyMon1 + ld h, d + ld l, e + add hl, bc + ld d, h + ld e, l + pop hl + jr .healmon + +.done + xor a + ld [wWhichPokemon], a + ld [wd11e], a + + ld a, [wPartyCount] + ld b, a +.ppup + push bc + call RestoreBonusPP + pop bc + ld hl, wWhichPokemon + inc [hl] + dec b + jr nz, .ppup + ret
\ No newline at end of file diff --git a/engine/init_player_data.asm b/engine/init_player_data.asm new file mode 100644 index 00000000..c1b93505 --- /dev/null +++ b/engine/init_player_data.asm @@ -0,0 +1,60 @@ +InitPlayerData: ; f6d6 (3:76d6) +InitPlayerData2: + + call Random + ld a, [hRandomSub] + ld [wPlayerID], a + + call Random + ld a, [hRandomAdd] + ld [wPlayerID + 1], a + + ld a, $ff + ld [wUnusedD71B], a + + ld a, 90 ; initialize happiness to 90 + ld [wPikachuHappiness], a + ld a, $80 + ld [wPikachuMood], a ; initialize mood + + ld hl, wPartyCount + call InitializeEmptyList + ld hl, wNumInBox + call InitializeEmptyList + ld hl, wNumBagItems + call InitializeEmptyList + ld hl, wNumBoxItems + call InitializeEmptyList + +START_MONEY EQU $3000 + ld hl, wPlayerMoney + 1 + ld a, START_MONEY / $100 + ld [hld], a + xor a + ld [hli], a + inc hl + ld [hl], a + + ld [wMonDataLocation], a + + ld hl, wObtainedBadges + ld [hli], a + + ld [hl], a + + ld hl, wPlayerCoins + ld [hli], a + ld [hl], a + + ld hl, wGameProgressFlags + ld bc, wGameProgressFlagsEnd - wGameProgressFlags + call FillMemory ; clear all game progress flags + + jp InitializeMissableObjectsFlags + +InitializeEmptyList: ; f730 (3:7730) + xor a ; count + ld [hli], a + dec a ; terminator + ld [hl], a + ret
\ No newline at end of file diff --git a/engine/move_mon.asm b/engine/move_mon.asm new file mode 100644 index 00000000..a14ed9ca --- /dev/null +++ b/engine/move_mon.asm @@ -0,0 +1,172 @@ +_MoveMon: ; f3a4 (3:73a4) + ld a, [wMoveMonType] + and a + jr z, .checkPartyMonSlots + cp DAYCARE_TO_PARTY + jr z, .checkPartyMonSlots + cp PARTY_TO_DAYCARE + ld hl, wDayCareMon + jr z, .asm_f3fb + 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, .asm_f3dc + ld a, [wcf91] +.asm_f3dc + ld [hli], a ; write new mon ID + ld [hl], $ff ; write new sentinel + ld a, [wMoveMonType] + dec a + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 ; $2c + ld a, [wPartyCount] + jr nz, .skipToNewMonEntry + ld hl, wBoxMons + ld bc, wBoxMon2 - wBoxMon1 ; $21 + ld a, [wNumInBox] +.skipToNewMonEntry + dec a + call AddNTimes +.asm_f3fb + push hl + ld e, l + ld d, h + ld a, [wMoveMonType] + and a + ld hl, wBoxMons + ld bc, wBoxMon2 - wBoxMon1 ; $21 + jr z, .asm_f417 + cp DAYCARE_TO_PARTY + ld hl, wDayCareMon + jr z, .asm_f41d + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 ; $2c +.asm_f417 + ld a, [wWhichPokemon] + call AddNTimes +.asm_f41d + push hl + push de + ld bc, wBoxMon2 - wBoxMon1 + call CopyData + pop de + pop hl + ld a, [wMoveMonType] + and a + jr z, .asm_f43a + cp DAYCARE_TO_PARTY + jr z, .asm_f43a + ld bc, wBoxMon2 - wBoxMon1 + add hl, bc + ld a, [hl] + inc de + inc de + inc de + ld [de], a +.asm_f43a + ld a, [wMoveMonType] + cp PARTY_TO_DAYCARE + ld de, wDayCareMonOT + jr z, .asm_f459 + dec a + ld hl, wPartyMonOT + ld a, [wPartyCount] + jr nz, .asm_f453 + ld hl, wBoxMonOT + ld a, [wNumInBox] +.asm_f453 + dec a + call SkipFixedLengthTextEntries + ld d, h + ld e, l +.asm_f459 + ld hl, wBoxMonOT + ld a, [wMoveMonType] + and a + jr z, .asm_f46c + ld hl, wDayCareMonOT + cp DAYCARE_TO_PARTY + jr z, .asm_f472 + ld hl, wPartyMonOT +.asm_f46c + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries +.asm_f472 + ld bc, NAME_LENGTH + call CopyData + ld a, [wMoveMonType] + cp PARTY_TO_DAYCARE + ld de, wDayCareMonName + jr z, .asm_f497 + dec a + ld hl, wPartyMonNicks + ld a, [wPartyCount] + jr nz, .asm_f491 + ld hl, wBoxMonNicks + ld a, [wNumInBox] +.asm_f491 + dec a + call SkipFixedLengthTextEntries + ld d, h + ld e, l +.asm_f497 + ld hl, wBoxMonNicks + ld a, [wMoveMonType] + and a + jr z, .asm_f4aa + ld hl, wDayCareMonName + cp DAYCARE_TO_PARTY + jr z, .asm_f4b0 + ld hl, wPartyMonNicks +.asm_f4aa + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries +.asm_f4b0 + ld bc, NAME_LENGTH + call CopyData + pop hl + ld a, [wMoveMonType] + cp PARTY_TO_BOX + jr z, .asm_f4ea + cp PARTY_TO_DAYCARE + jr z, .asm_f4ea + 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 +.asm_f4ea + and a + ret
\ No newline at end of file diff --git a/engine/overworld/boulders.asm b/engine/overworld/boulders.asm new file mode 100644 index 00000000..edfda2d3 --- /dev/null +++ b/engine/overworld/boulders.asm @@ -0,0 +1,94 @@ +CheckForCollisionWhenPushingBoulder: ; c356 (3:4356) + call GetTileTwoStepsInFrontOfPlayer + call IsTilePassable + jr c, .done + ld hl, TilePairCollisionsLand + call CheckForTilePairCollisions2 + ld a, $ff + jr c, .done ; if there is an elevation difference between the current tile and the one two steps ahead + ld a, [wTileInFrontOfBoulderAndBoulderCollisionResult] + cp $15 ; stairs tile + ld a, $ff + jr z, .done ; if the tile two steps ahead is stairs + call CheckForBoulderCollisionWithSprites +.done + ld [wTileInFrontOfBoulderAndBoulderCollisionResult], a + ret + +; sets a to $ff if there is a collision and $00 if there is no collision +CheckForBoulderCollisionWithSprites: ; c378 (3:4378) + ld a, [wBoulderSpriteIndex] + dec a + swap a + ld d, 0 + ld e, a + ld hl, wSpriteStateData2 + $14 + add hl, de + ld a, [hli] ; map Y position + ld [$ffdc], a + ld a, [hl] ; map X position + ld [$ffdd], a + ld a, [wNumSprites] + ld c, a + ld de, $f + ld hl, wSpriteStateData2 + $14 + ld a, [$ffdb] + and $3 ; facing up or down? + jr z, .pushingHorizontallyLoop +.pushingVerticallyLoop + inc hl + ld a, [$ffdd] + cp [hl] + jr nz, .nextSprite1 ; if X coordinates don't match + dec hl + ld a, [hli] + ld b, a + ld a, [$ffdb] + rrca + jr c, .pushingDown +; pushing up + ld a, [$ffdc] + dec a + jr .compareYCoords +.pushingDown + ld a, [$ffdc] + inc a +.compareYCoords + cp b + jr z, .failure +.nextSprite1 + dec c + jr z, .success + add hl, de + jr .pushingVerticallyLoop +.pushingHorizontallyLoop + ld a, [hli] + ld b, a + ld a, [$ffdc] + cp b + jr nz, .nextSprite2 + ld b, [hl] + ld a, [$ffdb] + bit 2, a + jr nz, .pushingLeft +; pushing right + ld a, [$ffdd] + inc a + jr .compareXCoords +.pushingLeft + ld a, [$ffdd] + dec a +.compareXCoords + cp b + jr z, .failure +.nextSprite2 + dec c + jr z, .success + add hl, de + jr .pushingHorizontallyLoop +.failure + ld a, $ff + ret +.success + xor a + ret
\ No newline at end of file diff --git a/engine/overworld/check_player_state.asm b/engine/overworld/check_player_state.asm new file mode 100644 index 00000000..157649a7 --- /dev/null +++ b/engine/overworld/check_player_state.asm @@ -0,0 +1,236 @@ +; only used for setting bit 2 of wd736 upon entering a new map +IsPlayerStandingOnWarp: ; c0a6 (3:40a6) + ld a, [wNumberOfWarps] + and a + ret z + ld c, a + ld hl, wWarpEntries +.loop + ld a, [wYCoord] + cp [hl] + jr nz, .nextWarp1 + inc hl + ld a, [wXCoord] + cp [hl] + jr nz, .nextWarp2 + inc hl + ld a, [hli] ; target warp + ld [wDestinationWarpID], a + ld a, [hl] ; target map + ld [$ff8b], a + ld hl, wd736 + set 2, [hl] ; standing on warp flag + ret +.nextWarp1 + inc hl +.nextWarp2 + inc hl + inc hl + inc hl + dec c + jr nz, .loop + ret + +CheckForceBikeOrSurf: ; c0d2 (3:40d2) + ld hl, wd732 + bit 5, [hl] + ret nz + ld hl, ForcedBikeOrSurfMaps + ld a, [wYCoord] + ld b, a + ld a, [wXCoord] + ld c, a + ld a, [wCurMap] + ld d, a +.loop + ld a, [hli] + cp $ff + ret z ;if we reach FF then it's not part of the list + cp d ;compare to current map + jr nz, .incorrectMap + ld a, [hli] + cp b ;compare y-coord + jr nz, .incorrectY + ld a, [hli] + cp c ;compare x-coord + jr nz, .loop ; incorrect x-coord, check next item + ld a, [wCurMap] + cp SEAFOAM_ISLANDS_4 + ld a, $2 + ld [wSeafoamIslands4CurScript], a + jr z, .forceSurfing + ld a, [wCurMap] + cp SEAFOAM_ISLANDS_5 + ld a, $2 + ld [wSeafoamIslands5CurScript], a + jr z, .forceSurfing + ;force bike riding + ld hl, wd732 + set 5, [hl] + ld a, $1 + ld [wWalkBikeSurfState], a + ld [wWalkBikeSurfStateCopy], a + call ForceBikeOrSurf + ret +.incorrectMap + inc hl +.incorrectY + inc hl + jr .loop +.forceSurfing + ld a, $2 + ld [wWalkBikeSurfState], a + ld [wWalkBikeSurfStateCopy], a + call ForceBikeOrSurf + ret + +INCLUDE "data/force_bike_surf.asm" + +IsPlayerFacingEdgeOfMap: ; c148 (3:4148) + push hl + push de + push bc + ld a, [wSpriteStateData1 + 9] ; player sprite's facing direction + srl a + ld c, a + ld b, $0 + ld hl, .functionPointerTable + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wYCoord] + ld b, a + ld a, [wXCoord] + ld c, a + ld de, .returnaddress + push de + jp [hl] +.returnaddress + pop bc + pop de + pop hl + ret + +.functionPointerTable + dw .facingDown + dw .facingUp + dw .facingLeft + dw .facingRight + +.facingDown + ld a, [wCurMapHeight] + add a + dec a + cp b + jr z, .setCarry + jr .resetCarry + +.facingUp + ld a, b + and a + jr z, .setCarry + jr .resetCarry + +.facingLeft + ld a, c + and a + jr z, .setCarry + jr .resetCarry + +.facingRight + ld a, [wCurMapWidth] + add a + dec a + cp c + jr z, .setCarry + jr .resetCarry +.resetCarry + and a + ret +.setCarry + scf + ret + +IsWarpTileInFrontOfPlayer: ; c197 (3:4197) + push hl + push de + push bc + call _GetTileAndCoordsInFrontOfPlayer + ld a, [wCurMap] + cp SS_ANNE_5 + jr z, .ssAnne5 + ld a, [wSpriteStateData1 + 9] ; player sprite's facing direction + srl a + ld c, a + ld b, 0 + ld hl, .warpTileListPointers + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wTileInFrontOfPlayer] + ld de, $1 + call IsInArray +.done + pop bc + pop de + pop hl + ret + +.warpTileListPointers: ; c1c0 (3:41c0) + dw .facingDownWarpTiles + dw .facingUpWarpTiles + dw .facingLeftWarpTiles + dw .facingRightWarpTiles + +.facingDownWarpTiles + db $01,$12,$17,$3D,$04,$18,$33,$FF + +.facingUpWarpTiles + db $01,$5C,$FF + +.facingLeftWarpTiles + db $1A,$4B,$FF + +.facingRightWarpTiles + db $0F,$4E,$FF + +.ssAnne5 + ld a, [wTileInFrontOfPlayer] + cp $15 + jr nz, .notSSAnne5Warp + scf + jr .done +.notSSAnne5Warp + and a + jr .done + +IsPlayerStandingOnDoorTileOrWarpTile: ; c1e6 (3:41e6) + push hl + push de + push bc + callba IsPlayerStandingOnDoorTile ; 6:6785 + jr c, .done + ld a, [wCurMapTileset] + add a + ld c, a + ld b, $0 + ld hl, WarpTileIDPointers + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld de, $1 + aCoord 8, 9 + call IsInArray + jr nc, .done + ld hl, wd736 + res 2, [hl] +.done + pop bc + pop de + pop hl + ret + +INCLUDE "data/warp_tile_ids.asm"
\ No newline at end of file diff --git a/engine/overworld/clear_loadmapdata_vars.asm b/engine/overworld/clear_loadmapdata_vars.asm new file mode 100644 index 00000000..2e7cd165 --- /dev/null +++ b/engine/overworld/clear_loadmapdata_vars.asm @@ -0,0 +1,20 @@ +ClearVariablesAfterLoadingMapData: ; c07c (3:407c) + ld a, $90 + ld [hWY], a + ld [rWY], a + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ld [wStepCounter], a + ld [wLoneAttackNo], a ; wGymLeaderNo + ld [hJoyPressed], a + ld [hJoyReleased], a + ld [hJoyHeld], a + ld [wActionResultOrTookBattleTurn], a + ld [wUnusedD5A3], a + ld hl, wCardKeyDoorY + ld [hli], a + ld [hl], a + ld hl, wWhichTrade + ld bc, $1e + call FillMemory + ret
\ No newline at end of file diff --git a/engine/overworld/daycare_exp.asm b/engine/overworld/daycare_exp.asm new file mode 100644 index 00000000..a7c7bd91 --- /dev/null +++ b/engine/overworld/daycare_exp.asm @@ -0,0 +1,18 @@ +IncrementDayCareMonExp: ; c684 (3:4684) + ld a, [wDayCareInUse] + and a + ret z + ld hl, wDayCareMonExp + 2 + inc [hl] + ret nz + dec hl + inc [hl] + ret nz + dec hl + inc [hl] + ld a, [hl] + cp $50 + ret c + ld a, $50 + ld [hl], a + ret
\ No newline at end of file diff --git a/engine/overworld/get_coords_tile_in_front_of_player.asm b/engine/overworld/get_coords_tile_in_front_of_player.asm new file mode 100644 index 00000000..a0d38d7c --- /dev/null +++ b/engine/overworld/get_coords_tile_in_front_of_player.asm @@ -0,0 +1,87 @@ +GetTileAndCoordsInFrontOfPlayer: ; c2d4 (3:42d1) + call GetPredefRegisters + +_GetTileAndCoordsInFrontOfPlayer: ; c2d4 (3:42d4) + ld a, [wYCoord] + ld d, a + ld a, [wXCoord] + ld e, a + ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + and a ; cp SPRITE_FACING_DOWN + jr nz, .notFacingDown +; facing down + aCoord 8, 11 + inc d + jr .storeTile +.notFacingDown + cp SPRITE_FACING_UP + jr nz, .notFacingUp +; facing up + aCoord 8, 7 + dec d + jr .storeTile +.notFacingUp + cp SPRITE_FACING_LEFT + jr nz, .notFacingLeft +; facing left + aCoord 6, 9 + dec e + jr .storeTile +.notFacingLeft + cp SPRITE_FACING_RIGHT + jr nz, .storeTile +; facing right + aCoord 10, 9 + inc e +.storeTile + ld c, a + ld [wTileInFrontOfPlayer], a + ret + +GetTileTwoStepsInFrontOfPlayer: ; c309 (3:4309) + xor a + ld [$ffdb], a + ld hl, wYCoord + ld a, [hli] + ld d, a + ld e, [hl] + ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + and a ; cp SPRITE_FACING_DOWN + jr nz, .notFacingDown +; facing down + ld hl, $ffdb + set 0, [hl] + aCoord 8, 13 + inc d + jr .storeTile +.notFacingDown + cp SPRITE_FACING_UP + jr nz, .notFacingUp +; facing up + ld hl, $ffdb + set 1, [hl] + aCoord 8, 5 + dec d + jr .storeTile +.notFacingUp + cp SPRITE_FACING_LEFT + jr nz, .notFacingLeft +; facing left + ld hl, $ffdb + set 2, [hl] + aCoord 4, 9 + dec e + jr .storeTile +.notFacingLeft + cp SPRITE_FACING_RIGHT + jr nz, .storeTile +; facing right + ld hl, $ffdb + set 3, [hl] + aCoord 12, 9 + inc e +.storeTile + ld c, a + ld [wTileInFrontOfBoulderAndBoulderCollisionResult], a + ld [wTileInFrontOfPlayer], a + ret
\ No newline at end of file diff --git a/engine/overworld/load_tileset_header.asm b/engine/overworld/load_tileset_header.asm new file mode 100644 index 00000000..aeab3e24 --- /dev/null +++ b/engine/overworld/load_tileset_header.asm @@ -0,0 +1,51 @@ +LoadTilesetHeader: ; c4f4 (3:44f4) + call GetPredefRegisters + push hl + ld d, 0 + ld a, [wCurMapTileset] + add a + add a + ld e, a + ld hl, Tilesets + add hl, de + add hl, de + add hl, de + ld de, wTilesetBank + ld bc, $b + call CopyData + ld a, [hl] + ld [hTilesetType], a + xor a + ld [$ffd8], a + pop hl + ld a, [wCurMapTileset] + push hl + push de + ld hl, DungeonTilesets + ld de, $1 + call IsInArray + pop de + pop hl + jr c, .notDungeonTileset + ld a, [wCurMapTileset] + ld b, a + ld a, [hPreviousTileset] + cp b + jr z, .done +.notDungeonTileset + ld a, [wDestinationWarpID] + cp $ff + jr z, .done + call LoadDestinationWarpPosition + ld a, [wYCoord] + and $1 + ld [wYBlockCoord], a + ld a, [wXCoord] + and $1 + ld [wXBlockCoord], a +.done + ret + +INCLUDE "data/dungeon_tilesets.asm" + +INCLUDE "data/tileset_headers.asm"
\ No newline at end of file diff --git a/engine/overworld/load_wild_data.asm b/engine/overworld/load_wild_data.asm new file mode 100644 index 00000000..083e08bf --- /dev/null +++ b/engine/overworld/load_wild_data.asm @@ -0,0 +1,33 @@ +LoadWildData: ; cb62 (3:4b62) + ld hl,WildDataPointers + ld a,[wCurMap] + + ; get wild data for current map + ld c,a + ld b,0 + add hl,bc + add hl,bc + ld a,[hli] + ld h,[hl] + ld l,a ; hl now points to wild data for current map + ld a,[hli] + ld [wGrassRate],a + and a + jr z,.NoGrassData ; if no grass data, skip to surfing data + push hl + ld de,wGrassMons ; otherwise, load grass data + ld bc,$0014 + call CopyData + pop hl + ld bc,$0014 + add hl,bc +.NoGrassData + ld a,[hli] + ld [wWaterRate],a + and a + ret z ; if no water data, we're done + ld de,wWaterMons ; otherwise, load surfing data + ld bc,$0014 + jp CopyData + +INCLUDE "data/wild_mons.asm"
\ No newline at end of file diff --git a/engine/overworld/missable_objects.asm b/engine/overworld/missable_objects.asm new file mode 100644 index 00000000..f18a0823 --- /dev/null +++ b/engine/overworld/missable_objects.asm @@ -0,0 +1,212 @@ +MarkTownVisitedAndLoadMissableObjects: ; ef93 (3:6f93) + ld a, [wCurMap] + cp ROUTE_1 + jr nc, .notInTown + ld c, a + ld b, FLAG_SET + ld hl, wTownVisitedFlag ; mark town as visited (for flying) + predef FlagActionPredef +.notInTown + ld hl, MapHSPointers + ld a, [wCurMap] + ld b, $0 + ld c, a + add hl, bc + add hl, bc + ld a, [hli] ; load missable objects pointer in hl + ld h, [hl] + ; fall through + +; LoadMissableObjects: ; efb2 (3:6fb2) +; seems to not exist in yellow (predef replaced with something near TryPushingBoulder) + ld l, a + push hl + ld a, l + sub MapHS00 & $ff ; calculate difference between out pointer and the base pointer + ld l, a + ld a, h + sbc MapHS00 / $100 + ld h, a + ld a, h + ld [H_DIVIDEND], a + ld a, l + ld [H_DIVIDEND+1], a + xor a + ld [H_DIVIDEND+2], a + ld [H_DIVIDEND+3], a + ld a, $3 + ld [H_DIVISOR], a + ld b, $2 + call Divide ; divide difference by 3, resulting in the global offset (number of missable items before ours) + ld a, [wCurMap] + ld b, a + ld a, [H_DIVIDEND+3] + ld c, a ; store global offset in c + ld de, wMissableObjectList + pop hl +.writeMissableObjectsListLoop + ld a, [hli] + cp $ff + jr z, .done ; end of list + cp b + jr nz, .done ; not for current map anymore + ld a, [hli] + inc hl + ld [de], a ; write (map-local) sprite ID + inc de + ld a, c + inc c + ld [de], a ; write (global) missable object index + inc de + jr .writeMissableObjectsListLoop +.done + ld a, $ff + ld [de], a ; write sentinel + ret + +InitializeMissableObjectsFlags: ; eff1 (3:6ff1) + ld hl, wMissableObjectFlags + ld bc, wMissableObjectFlagsEnd - wMissableObjectFlags + xor a + call FillMemory ; clear missable objects flags + ld hl, MapHS00 + xor a + ld [wMissableObjectCounter], a +.missableObjectsLoop + ld a, [hli] + cp $ff ; end of list + ret z + push hl + inc hl + ld a, [hl] + cp Hide + jr nz, .skip + ld hl, wMissableObjectFlags + ld a, [wMissableObjectCounter] + ld c, a + ld b, FLAG_SET + call MissableObjectFlagAction ; set flag if Item is hidden +.skip + ld hl, wMissableObjectCounter + inc [hl] + pop hl + inc hl + inc hl + jr .missableObjectsLoop + +; tests if current sprite is a missable object that is hidden/has been removed +IsObjectHidden: ; f022 (3:7022) + ld a, [H_CURRENTSPRITEOFFSET] + swap a + ld b, a + ld hl, wMissableObjectList +.loop + ld a, [hli] + cp $ff + jr z, .notHidden ; not missable -> not hidden + cp b + ld a, [hli] + jr nz, .loop + ld c, a + ld b, FLAG_TEST + ld hl, wMissableObjectFlags + call MissableObjectFlagAction + ld a, c + and a + jr nz, .hidden +.notHidden + xor a +.hidden + ld [$ffe5], a + ret + +; adds missable object (items, leg. pokemon, etc.) to the map +; [wMissableObjectIndex]: index of the missable object to be added (global index) +ShowObject: ; f044 (3:7044) +ShowObject2: + ld hl, wMissableObjectFlags + ld a, [wMissableObjectIndex] + ld c, a + ld b, FLAG_RESET + call MissableObjectFlagAction ; reset "removed" flag + jp UpdateSprites + +; removes missable object (items, leg. pokemon, etc.) from the map +; [wMissableObjectIndex]: index of the missable object to be removed (global index) +HideObject: ; f053 (3:7053) + ld hl, wMissableObjectFlags + ld a, [wMissableObjectIndex] + ld c, a + ld b, FLAG_SET + call MissableObjectFlagAction ; set "removed" flag + jp UpdateSprites + +MissableObjectFlagAction: ; f062 (3:7062) +; identical to FlagAction + + push hl + push de + push bc + + ; bit + ld a, c + ld d, a + and 7 + ld e, a + + ; byte + ld a, d + srl a + srl a + srl a + add l + ld l, a + jr nc, .ok + inc h +.ok + + ; d = 1 << e (bitmask) + inc e + ld d, 1 +.shift + dec e + jr z, .shifted + sla d + jr .shift +.shifted + + ld a, b + and a + jr z, .reset + cp 2 + jr z, .read + +.set + ld a, [hl] + ld b, a + ld a, d + or b + ld [hl], a + jr .done + +.reset + ld a, [hl] + ld b, a + ld a, d + xor $ff + and b + ld [hl], a + jr .done + +.read + ld a, [hl] + ld b, a + ld a, d + and b + +.done + pop bc + pop de + pop hl + ld c, a + ret
\ No newline at end of file diff --git a/engine/overworld/npc_pathfinding.asm b/engine/overworld/npc_pathfinding.asm new file mode 100644 index 00000000..ed7db530 --- /dev/null +++ b/engine/overworld/npc_pathfinding.asm @@ -0,0 +1,201 @@ +FindPathToPlayer: ; f74a (3:774a) + xor a + ld hl, hFindPathNumSteps + ld [hli], a ; hFindPathNumSteps + ld [hli], a ; hFindPathFlags + ld [hli], a ; hFindPathYProgress + ld [hl], a ; hFindPathXProgress + ld hl, wNPCMovementDirections2 + ld de, $0 +.loop + ld a, [hFindPathYProgress] + ld b, a + ld a, [hNPCPlayerYDistance] ; Y distance in steps + call CalcDifference + ld d, a + and a + jr nz, .asm_f76a + ld a, [hFindPathFlags] + set 0, a ; current end of path matches the player's Y coordinate + ld [hFindPathFlags], a +.asm_f76a + ld a, [hFindPathXProgress] + ld b, a + ld a, [hNPCPlayerXDistance] ; X distance in steps + call CalcDifference + ld e, a + and a + jr nz, .asm_f77c + ld a, [hFindPathFlags] + set 1, a ; current end of path matches the player's X coordinate + ld [hFindPathFlags], a +.asm_f77c + ld a, [hFindPathFlags] + cp $3 ; has the end of the path reached the player's position? + jr z, .done +; Compare whether the X distance between the player and the current of the path +; is greater or if the Y distance is. Then, try to reduce whichever is greater. + ld a, e + cp d + jr c, .yDistanceGreater +; x distance is greater + ld a, [hNPCPlayerRelativePosFlags] + bit 1, a + jr nz, .playerIsLeftOfNPC + ld d, NPC_MOVEMENT_RIGHT + jr .next1 +.playerIsLeftOfNPC + ld d, NPC_MOVEMENT_LEFT +.next1 + ld a, [hFindPathXProgress] + add 1 + ld [hFindPathXProgress], a + jr .storeDirection +.yDistanceGreater + ld a, [hNPCPlayerRelativePosFlags] + bit 0, a + jr nz, .playerIsAboveNPC + ld d, NPC_MOVEMENT_DOWN + jr .next2 +.playerIsAboveNPC + ld d, NPC_MOVEMENT_UP +.next2 + ld a, [hFindPathYProgress] + add 1 + ld [hFindPathYProgress], a +.storeDirection + ld a, d + ld [hli], a + ld a, [hFindPathNumSteps] + inc a + ld [hFindPathNumSteps], a + jp .loop +.done + ld [hl], $ff + ret + +CalcPositionOfPlayerRelativeToNPC: ; f7b9 (3:77b9) + xor a + ld [hNPCPlayerRelativePosFlags], a + ld a, [wSpriteStateData1 + 4] ; player's sprite screen Y position in pixels + ld d, a + ld a, [wSpriteStateData1 + 6] ; player's sprite screen X position in pixels + ld e, a + ld hl, wSpriteStateData1 + ld a, [hNPCSpriteOffset] + add l + add $4 + ld l, a + jr nc, .noCarry + inc h +.noCarry + ld a, d + ld b, a + ld a, [hli] ; NPC sprite screen Y position in pixels + call CalcDifference + jr nc, .NPCSouthOfOrAlignedWithPlayer +.NPCNorthOfPlayer + push hl + ld hl, hNPCPlayerRelativePosFlags + bit 0, [hl] + set 0, [hl] + pop hl + jr .divideYDistance +.NPCSouthOfOrAlignedWithPlayer + push hl + ld hl, hNPCPlayerRelativePosFlags + bit 0, [hl] + res 0, [hl] + pop hl +.divideYDistance + push hl + ld hl, hDividend2 + ld [hli], a + ld a, 16 + ld [hli], a + call DivideBytes ; divide Y absolute distance by 16 + ld a, [hl] ; quotient + ld [hNPCPlayerYDistance], a + pop hl + inc hl + ld b, e + ld a, [hl] ; NPC sprite screen X position in pixels + call CalcDifference + jr nc, .NPCEastOfOrAlignedWithPlayer +.NPCWestOfPlayer + push hl + ld hl, hNPCPlayerRelativePosFlags + bit 1, [hl] + set 1, [hl] + pop hl + jr .divideXDistance +.NPCEastOfOrAlignedWithPlayer + push hl + ld hl, hNPCPlayerRelativePosFlags + bit 1, [hl] + res 1, [hl] + pop hl +.divideXDistance + ld [hDividend2], a + ld a, 16 + ld [hDivisor2], a + call DivideBytes ; divide X absolute distance by 16 + ld a, [hQuotient2] + ld [hNPCPlayerXDistance], a + ld a, [hNPCPlayerRelativePosPerspective] + and a + ret z + ld a, [hNPCPlayerRelativePosFlags] + cpl + and $3 + ld [hNPCPlayerRelativePosFlags], a + ret + +ConvertNPCMovementDirectionsToJoypadMasks: ; f830 (3:7830) + ld a, [hNPCMovementDirections2Index] + ld [wNPCMovementDirections2Index], a + dec a + ld de, wSimulatedJoypadStatesEnd + ld hl, wNPCMovementDirections2 + add l + ld l, a + jr nc, .loop + inc h +.loop + ld a, [hld] + call ConvertNPCMovementDirectionToJoypadMask + ld [de], a + inc de + ld a, [hNPCMovementDirections2Index] + dec a + ld [hNPCMovementDirections2Index], a + jr nz, .loop + ret + +ConvertNPCMovementDirectionToJoypadMask: ; f84f (3:784f) + push hl + ld b, a + ld hl, NPCMovementDirectionsToJoypadMasksTable +.loop + ld a, [hli] + cp $ff + jr z, .done + cp b + jr z, .loadJoypadMask + inc hl + jr .loop +.loadJoypadMask + ld a, [hl] +.done + pop hl + ret + +NPCMovementDirectionsToJoypadMasksTable: ; f862 (3:7862) + db NPC_MOVEMENT_UP, D_UP + db NPC_MOVEMENT_DOWN, D_DOWN + db NPC_MOVEMENT_LEFT, D_LEFT + db NPC_MOVEMENT_RIGHT, D_RIGHT + db $ff + +; unreferenced + ret
\ No newline at end of file diff --git a/engine/overworld/print_safari_steps.asm b/engine/overworld/print_safari_steps.asm new file mode 100644 index 00000000..3f2ada03 --- /dev/null +++ b/engine/overworld/print_safari_steps.asm @@ -0,0 +1,36 @@ +PrintSafariZoneSteps: ; c27b (3:427b) + ld a, [wCurMap] + cp SAFARI_ZONE_EAST + ret c + cp UNKNOWN_DUNGEON_2 + ret nc + coord hl, 0, 0 + lb bc, 3, 7 + call TextBoxBorder + coord hl, 1, 1 + ld de, wSafariSteps + lb bc, 2, 3 + call PrintNumber + coord hl, 4, 1 + ld de, SafariSteps + call PlaceString + coord hl, 1, 3 + ld de, SafariBallText + call PlaceString + ld a, [wNumSafariBalls] + cp 10 + jr nc, .numSafariBallsTwoDigits + coord hl, 5, 3 + ld a, " " + ld [hl], a +.numSafariBallsTwoDigits + coord hl, 6, 3 + ld de, wNumSafariBalls + lb bc, 1, 2 + jp PrintNumber + +SafariSteps: ; c2c4 (3:42c4) + db "/500@" + +SafariBallText: ; c5c9 (3:42c9) + db "BALL×× @"
\ No newline at end of file diff --git a/engine/overworld/replace_tile_block.asm b/engine/overworld/replace_tile_block.asm new file mode 100644 index 00000000..32c652ea --- /dev/null +++ b/engine/overworld/replace_tile_block.asm @@ -0,0 +1,126 @@ +; replaces a tile block with the one specified in [wNewTileBlockID] +; and redraws the map view if necessary +; b = Y +; c = X +ReplaceTileBlock: ; ed1b (3:6d1b) + call GetPredefRegisters + ld hl, wOverworldMap + ld a, [wCurMapWidth] + add $6 + ld e, a + ld d, $0 + add hl, de + add hl, de + add hl, de + ld e, $3 + add hl, de + ld e, a + ld a, b + and a + jr z, .addX +; add width * Y +.addWidthYTimesLoop + add hl, de + dec b + jr nz, .addWidthYTimesLoop +.addX + add hl, bc ; add X + ld a, [wNewTileBlockID] + ld [hl], a + ld a, [wCurrentTileBlockMapViewPointer] + ld c, a + ld a, [wCurrentTileBlockMapViewPointer + 1] + ld b, a + call CompareHLWithBC + ret c ; return if the replaced tile block is below the map view in memory + push hl + ld l, e + ld h, $0 + ld e, $6 + ld d, h + add hl, hl + add hl, hl + add hl, de + add hl, bc + pop bc + call CompareHLWithBC + ret c ; return if the replaced tile block is above the map view in memory + +RedrawMapView: ; ed59 (3:6d59) + ld a, [wIsInBattle] + inc a + ret z + ld a, [H_AUTOBGTRANSFERENABLED] + push af + ld a, [hTilesetType] + push af + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ld [hTilesetType], a ; no flower/water BG tile animations + call LoadCurrentMapView + call RunDefaultPaletteCommand + ld hl, wMapViewVRAMPointer + ld a, [hli] + ld h, [hl] + ld l, a + ld de, -2 * 32 + add hl, de + ld a, h + and $3 + or $98 + ld a, l + ld [wBuffer], a + ld a, h + ld [wBuffer + 1], a ; this copy of the address is not used + ld a, 2 + ld [$ffbe], a + ld c, 9 ; number of rows of 2x2 tiles (this covers the whole screen) +.redrawRowLoop + push bc + push hl + push hl + ld hl, wTileMap - 2 * SCREEN_WIDTH + ld de, SCREEN_WIDTH + ld a, [$ffbe] +.calcWRAMAddrLoop + add hl, de + dec a + jr nz, .calcWRAMAddrLoop + call CopyToRedrawRowOrColumnSrcTiles + pop hl + ld de, $20 + ld a, [$ffbe] + ld c, a +.calcVRAMAddrLoop + add hl, de + ld a, h + and $3 + or $98 + dec c + jr nz, .calcVRAMAddrLoop + ld [hRedrawRowOrColumnDest + 1], a + ld a, l + ld [hRedrawRowOrColumnDest], a + ld a, REDRAW_ROW + ld [hRedrawRowOrColumnMode], a + call DelayFrame + ld hl, $ffbe + inc [hl] + inc [hl] + pop hl + pop bc + dec c + jr nz, .redrawRowLoop + pop af + ld [hTilesetType], a + pop af + ld [H_AUTOBGTRANSFERENABLED], a + ret + +CompareHLWithBC: ; edcb (3:6dcb) + ld a, h + sub b + ret nz + ld a, l + sub c + ret
\ No newline at end of file diff --git a/engine/overworld/step_functions.asm b/engine/overworld/step_functions.asm new file mode 100644 index 00000000..84cf4e82 --- /dev/null +++ b/engine/overworld/step_functions.asm @@ -0,0 +1,151 @@ +ApplyOutOfBattlePoisonDamage: ; c3de (3:43de) + ld a, [wd730] + add a + jp c, .noBlackOut ; no black out if joypad states are being simulated + ld a, [wd493] + bit 7, a + jp nz, .noBlackOut + ld a, [wd72e] + bit 6, a + jp nz, .noBlackOut + ld a, [wPartyCount] + and a + jp z, .noBlackOut + call IncrementDayCareMonExp + call Func_c4c7 + ld a, [wStepCounter] + and $3 ; is the counter a multiple of 4? + jp nz, .skipPoisonEffectAndSound ; only apply poison damage every fourth step + ld [wWhichPokemon], a + ld hl, wPartyMon1Status + ld de, wPartySpecies +.applyDamageLoop + ld a, [hl] + and (1 << PSN) + jr z, .nextMon2 ; not poisoned + dec hl + dec hl + ld a, [hld] + ld b, a + ld a, [hli] + or b + jr z, .nextMon ; already fainted +; subtract 1 from HP + ld a, [hl] + dec a + ld [hld], a + inc a + jr nz, .noBorrow +; borrow 1 from upper byte of HP + dec [hl] + inc hl + jr .nextMon +.noBorrow + ld a, [hli] + or [hl] + jr nz, .nextMon ; didn't faint from damage +; the mon fainted from the damage + push hl + inc hl + inc hl + ld [hl], a + ld a, [de] + ld [wd11e], a + push de + ld a, [wWhichPokemon] + ld hl, wPartyMonNicks + call GetPartyMonName + xor a + ld [wJoyIgnore], a + call EnableAutoTextBoxDrawing + ld a, $d0 + ld [hSpriteIndexOrTextID], a + call DisplayTextID + callab IsThisPartymonStarterPikachu_Party + jr nc, .curMonNotPlayerPikachu + ld e, $3 + callab PlayPikachuSoundClip + calladb_ModifyPikachuHappiness PIKAHAPPY_PSNFNT +.curMonNotPlayerPikachu + pop de + pop hl +.nextMon + inc hl + inc hl +.nextMon2 + inc de + ld a, [de] + inc a + jr z, .applyDamageLoopDone + ld bc, wPartyMon2 - wPartyMon1 + add hl, bc + push hl + ld hl, wWhichPokemon + inc [hl] + pop hl + jr .applyDamageLoop +.applyDamageLoopDone + ld hl, wPartyMon1Status + ld a, [wPartyCount] + ld d, a + ld e, 0 +.countPoisonedLoop + ld a, [hl] + and (1 << PSN) + or e + ld e, a + ld bc, wPartyMon2 - wPartyMon1 + add hl, bc + dec d + jr nz, .countPoisonedLoop + ld a, e + and a ; are any party members poisoned? + jr z, .skipPoisonEffectAndSound + ld b, $2 + predef InvertBGPal_4Frames ; change BG white to dark grey for 4 frames + ld a, SFX_POISONED + call PlaySound +.skipPoisonEffectAndSound + predef AnyPartyAlive + ld a, d + and a + jr nz, .noBlackOut + call EnableAutoTextBoxDrawing + ld a, $d1 + ld [hSpriteIndexOrTextID], a + call DisplayTextID + ld hl, wd72e + set 5, [hl] + ld a, $ff + jr .done +.noBlackOut + xor a +.done + ld [wOutOfBattleBlackout], a + ret + +Func_c4c7: ; c4c7 (3:44c7) + ld a, [wStepCounter] + and a + jr nz, .asm_c4de + call Random + and $1 + jr z, .asm_c4de + calladb_ModifyPikachuHappiness $6 +.asm_c4de + ld hl, wPikachuMood + ld a, [hl] + cp $80 + jr z, .asm_c4ef + jr c, .asm_c4ea + dec a + dec a +.asm_c4ea + inc a + ld [hl], a + cp $80 + ret nz +.asm_c4ef + xor a + ld [wd49c], a + ret
\ No newline at end of file diff --git a/engine/overworld/try_pushing_boulder.asm b/engine/overworld/try_pushing_boulder.asm new file mode 100644 index 00000000..d978a083 --- /dev/null +++ b/engine/overworld/try_pushing_boulder.asm @@ -0,0 +1,106 @@ +TryPushingBoulder: ; f0a1 (3:70a1) + ld a, [wd728] + bit 0, a ; using Strength? + ret z +; where LoadMissableObjects predef points to now + ld a, [wFlags_0xcd60] + bit 1, a ; has boulder dust animation from previous push played yet? + ret nz + xor a + ld [hSpriteIndexOrTextID], a + call IsSpriteInFrontOfPlayer + ld a, [hSpriteIndexOrTextID] + ld [wBoulderSpriteIndex], a + and a + jp z, ResetBoulderPushFlags + ld hl, wSpriteStateData1 + 1 + ld d, $0 + ld a, [hSpriteIndexOrTextID] + swap a + ld e, a + add hl, de + res 7, [hl] + call GetSpriteMovementByte2Pointer + ld a, [hl] + cp BOULDER_MOVEMENT_BYTE_2 + jp nz, ResetBoulderPushFlags + ld hl, wFlags_0xcd60 + bit 6, [hl] + set 6, [hl] ; indicate that the player has tried pushing + ret z ; the player must try pushing twice before the boulder will move + ld a, [hJoyHeld] + and D_RIGHT | D_LEFT | D_UP | D_DOWN + ret z + predef CheckForCollisionWhenPushingBoulder + ld a, [wTileInFrontOfBoulderAndBoulderCollisionResult] + and a ; was there a collision? + jp nz, ResetBoulderPushFlags + ld a, [hJoyHeld] + ld b, a + ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + cp SPRITE_FACING_UP + jr z, .pushBoulderUp + cp SPRITE_FACING_LEFT + jr z, .pushBoulderLeft + cp SPRITE_FACING_RIGHT + jr z, .pushBoulderRight +.pushBoulderDown + bit 7, b + ret z + ld de, PushBoulderDownMovementData + jr .done +.pushBoulderUp + bit 6, b + ret z + ld de, PushBoulderUpMovementData + jr .done +.pushBoulderLeft + bit 5, b + ret z + ld de, PushBoulderLeftMovementData + jr .done +.pushBoulderRight + bit 4, b + ret z + ld de, PushBoulderRightMovementData +.done + call MoveSprite + ld a, SFX_PUSH_BOULDER + call PlaySound + ld hl, wFlags_0xcd60 + set 1, [hl] + ret + +PushBoulderUpMovementData: ; f129 (3:7129) + db NPC_MOVEMENT_UP,$FF + +PushBoulderDownMovementData: ; f12b (3:712b) + db NPC_MOVEMENT_DOWN,$FF + +PushBoulderLeftMovementData: ; f12d (3:712d) + db NPC_MOVEMENT_LEFT,$FF + +PushBoulderRightMovementData: ; f12f (3:712f) + db NPC_MOVEMENT_RIGHT,$FF + +DoBoulderDustAnimation: ; f131 (3:7131) + ld a, [wd730] + bit 0, a + ret nz + callab AnimateBoulderDust + call DiscardButtonPresses + ld [wJoyIgnore], a + call ResetBoulderPushFlags + set 7, [hl] + ld a, [wBoulderSpriteIndex] + ld [H_SPRITEINDEX], a + call GetSpriteMovementByte2Pointer + ld [hl], $10 + ld a, SFX_CUT + jp PlaySound + +ResetBoulderPushFlags: ; f159 (3:7159) + ld hl, wFlags_0xcd60 + res 1, [hl] + res 6, [hl] + ret
\ No newline at end of file |