diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..0783442f2 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["donaldhays.rgbds-z80"] +} \ No newline at end of file diff --git a/Makefile b/Makefile index 5eb584b18..88a17a499 100644 --- a/Makefile +++ b/Makefile @@ -87,6 +87,10 @@ ifeq ($(DEBUG),1) RGBASMFLAGS += -E endif +ifeq ($(BUGFIX),1) +RGBASMFLAGS += -D _BUGFIX +endif + $(pokeyellow_debug_obj): RGBASMFLAGS += -D _DEBUG $(pokeyellow_vc_obj): RGBASMFLAGS += -D _YELLOW_VC diff --git a/README.md b/README.md index d772f3298..7bb0c8268 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Pokémon Yellow [![Build Status][ci-badge]][ci] +# Pokémon Yellow Fort Knox Edition [![Build Status][ci-badge]][ci] This is a disassembly of Pokémon Yellow. @@ -10,6 +10,13 @@ It builds the following ROMs: To set up the repository, see [**INSTALL.md**](INSTALL.md). +## Fort Knox Edition + +This version includes the ability to optionally compile with a set of bugfix patches I'm calling Fort Knox Edition: + +`make BUGFIX=1` + +Many of these patches are sourced from the research done on [pokered](https://github.com/pret/pokered/wiki/%5BARCHIVED%5D-Bugs-and-Glitches) which is now defunct and archived. Some patches were also written specifically for this project (badge boosts, fast options) and some were collaborations with other Pokemon Speedrun community members including CasualPokePlayer and luckytyphlosion (statistically validated PRNG). ## See also diff --git a/audio/engine_1.asm b/audio/engine_1.asm index c155dda63..16821b2cd 100644 --- a/audio/engine_1.asm +++ b/audio/engine_1.asm @@ -1241,13 +1241,21 @@ Audio1_InitPitchSlideVars: ; This means that the result will be 0x200 greater than it should be if the ; low byte of the current frequency is greater than the low byte of the ; target frequency. +IF DEF(_BUGFIX) + push af + ld hl, wChannelPitchSlideTargetFrequencyHighBytes + add hl, bc + pop af + ld a, [hl] + sbc b +ELSE ld a, d sbc b ld d, a - ld hl, wChannelPitchSlideTargetFrequencyHighBytes add hl, bc ld a, [hl] +ENDC sub d ld d, a ld b, 0 diff --git a/data/battle_anims/subanimations.asm b/data/battle_anims/subanimations.asm index 74097e226..9b419ff0a 100644 --- a/data/battle_anims/subanimations.asm +++ b/data/battle_anims/subanimations.asm @@ -547,7 +547,12 @@ Subanim_0Circle_1Square_TossBack: db FRAMEBLOCK_47, BASECOORD_B0, FRAMEBLOCKMODE_00 Subanim_0CirclesCentering: - subanim SUBANIMTYPE_COORDFLIP, 6 ; should be SUBANIMTYPE_HVFLIP +; fix animation when AI uses double edge +IF DEF(_BUGFIX) + subanim SUBANIMTYPE_HVFLIP, 6 +ELSE + subanim SUBANIMTYPE_COORDFLIP, 6 +ENDC db FRAMEBLOCK_44, BASECOORD_64, FRAMEBLOCKMODE_00 db FRAMEBLOCK_45, BASECOORD_65, FRAMEBLOCKMODE_00 db FRAMEBLOCK_46, BASECOORD_66, FRAMEBLOCKMODE_00 diff --git a/data/maps/dungeon_maps.asm b/data/maps/dungeon_maps.asm index d647923cd..fbec3af4e 100644 --- a/data/maps/dungeon_maps.asm +++ b/data/maps/dungeon_maps.asm @@ -1,8 +1,3 @@ -; GetBattleTransitionID_IsDungeonMap fails to recognize -; VICTORY_ROAD_2F, VICTORY_ROAD_3F, all ROCKET_HIDEOUT maps, -; POKEMON_MANSION_1F, SEAFOAM_ISLANDS_[B1F-B4F], POWER_PLANT, -; DIGLETTS_CAVE, and SILPH_CO_[9-11]F as dungeon maps - ; GetBattleTransitionID_IsDungeonMap checks if wCurMap ; is equal to one of these maps DungeonMaps1: @@ -10,6 +5,14 @@ DungeonMaps1: db ROCK_TUNNEL_1F db SEAFOAM_ISLANDS_1F db ROCK_TUNNEL_B1F +; fix missing dungeon maps +IF DEF(_BUGFIX) + db POKEMON_MANSION_1F + db VICTORY_ROAD_2F + db VICTORY_ROAD_3F + db POWER_PLANT + db DIGLETTS_CAVE +ENDC db -1 ; end ; GetBattleTransitionID_IsDungeonMap checks if wCurMap @@ -24,4 +27,12 @@ DungeonMaps2: ; SILPH_CO_[2-8]F, POKEMON_MANSION[2F-B1F], SAFARI_ZONE, and ; CERULEAN_CAVE maps, except for SILPH_CO_1F db SILPH_CO_2F, CERULEAN_CAVE_1F +IF DEF(_BUGFIX) + ; SILPH_CO_[9-11]F + db SILPH_CO_9F, SILPH_CO_11F + ; SEAFOAM_ISLANDS_[B1F-B4F] + db SEAFOAM_ISLANDS_B1F, SEAFOAM_ISLANDS_B4F + ; all ROCKET_HIDEOUT maps + db ROCKET_HIDEOUT_B1F, ROCKET_HIDEOUT_B4F +ENDC db -1 ; end diff --git a/data/maps/objects/Route17.asm b/data/maps/objects/Route17.asm index 48d889265..0d352708d 100644 --- a/data/maps/objects/Route17.asm +++ b/data/maps/objects/Route17.asm @@ -10,6 +10,10 @@ Route17_Object: bg_event 9, 87, 14 ; Route17Text14 bg_event 9, 111, 15 ; Route17Text15 bg_event 9, 141, 16 ; Route17Text16 +; fix the sign at Route 16 showing Celadon <-> Fuchsia when read from the front +IF DEF(_BUGFIX) + bg_event 5, -1, 17 ; Route17Text17 +ENDC def_object_events object_event 12, 19, SPRITE_BIKER, STAY, LEFT, 1, OPP_CUE_BALL, 4 diff --git a/engine/battle/animations.asm b/engine/battle/animations.asm index ffa7e5a82..68b591c70 100644 --- a/engine/battle/animations.asm +++ b/engine/battle/animations.asm @@ -1413,7 +1413,10 @@ AdjustOAMBlockYPos2: add b cp 112 jr c, .skipSettingPreviousEntrysAttribute +; fix swag boulder +IF !DEF(_BUGFIX) dec hl +ENDC ld a, 160 ; bug, sets previous OAM entry's attribute ld [hli], a .skipSettingPreviousEntrysAttribute @@ -1931,7 +1934,11 @@ _AnimationSlideMonOff: sub 7 ; This has the same problem as above, but it has no visible effect because ; the lower right tile is in the first column to slide off the screen. +IF DEF(_BUGFIX) + cp $31 +ELSE cp $30 +ENDC ret c ld a, " " ret @@ -1969,6 +1976,11 @@ AnimationWavyScreen: ld c, $ff ld hl, WavyScreenLineOffsets .loop +; Fix the wave effect for the top 3 lines of the screen +IF DEF(_BUGFIX) + ld a, [hl] + ldh [hSCX], a +ENDC push hl .innerLoop call WavyScreen_SetSCX @@ -1985,6 +1997,10 @@ AnimationWavyScreen: dec c jr nz, .loop xor a +; Fix the wave effect for the top 3 lines of the screen +IF DEF(_BUGFIX) + ldh [hSCX], a +ENDC ldh [hWY], a call SaveScreenTilesToBuffer2 call ClearScreen diff --git a/engine/battle/battle_transitions.asm b/engine/battle/battle_transitions.asm index b0289d7e4..05b08f8d5 100644 --- a/engine/battle/battle_transitions.asm +++ b/engine/battle/battle_transitions.asm @@ -91,6 +91,13 @@ GetBattleTransitionID_WildOrTrainer: ret GetBattleTransitionID_CompareLevels: + ; This section fixes undefined behavior in the Pikachu cutscene + ; Due to not yet having obtained a pokemon +IF DEF(_BUGFIX) + ld a, [wPartyCount] + cp 0 + jr z, .highLevelEnemy +ENDC ld hl, wPartyMon1HP .faintedLoop ld a, [hli] diff --git a/engine/battle/common_text.asm b/engine/battle/common_text.asm index 95c06bf5d..1482b247a 100644 --- a/engine/battle/common_text.asm +++ b/engine/battle/common_text.asm @@ -200,6 +200,10 @@ PlayerMon2Text: ld b, [hl] ld a, [de] sbc b +; original code ignores underflow, if we underflow, print default text +IF DEF(_BUGFIX) + jr c, .gainedHP +ENDC ldh [hMultiplicand + 1], a ld a, 25 ldh [hMultiplier], a @@ -234,6 +238,14 @@ PlayerMon2Text: ret c ld hl, GoodText ; HP went down 70% or more ret +; fallback to default text for underflow +IF DEF(_BUGFIX) +.gainedHP + pop bc + pop de + ld hl, EnoughText + ret +ENDC EnoughText: text_far _EnoughText diff --git a/engine/battle/core.asm b/engine/battle/core.asm index addff324d..91cb6c42c 100644 --- a/engine/battle/core.asm +++ b/engine/battle/core.asm @@ -1228,6 +1228,11 @@ SlideDownFaintedMonPic: push de push hl ld b, 6 ; number of rows +; fix tearing during sliding animations +IF DEF(_BUGFIX) + xor a + ld [hAutoBGTransferEnabled], a +ENDC .rowLoop push bc push hl @@ -1252,6 +1257,12 @@ SlideDownFaintedMonPic: add hl, bc ld de, SevenSpacesText call PlaceString +; fix tearing during sliding animations +IF DEF(_BUGFIX) + xor a + inc a + ld [hAutoBGTransferEnabled], a +ENDC ld c, 2 call DelayFrames pop hl @@ -1277,6 +1288,11 @@ SlideTrainerPicOffScreen: push bc push hl ld b, 7 ; number of rows +; fix tearing during sliding animations +IF DEF(_BUGFIX) + xor a + ld [hAutoBGTransferEnabled], a +ENDC .rowLoop push hl ldh a, [hSlideAmount] @@ -1302,6 +1318,12 @@ SlideTrainerPicOffScreen: add hl, de dec b jr nz, .rowLoop +; fix tearing during sliding animations +IF DEF(_BUGFIX) + xor a + inc a + ld [hAutoBGTransferEnabled], a +ENDC ld c, 2 call DelayFrames pop hl @@ -2490,7 +2512,16 @@ PartyMenuOrRockOrRun: ld [wd0b5], a call GetMonHeader ld de, vFrontPic +; ensure we don't identify ghost encounters when reloading battle sprites +IF DEF(_BUGFIX) + call IsGhostBattle + push af + call nz, LoadMonFrontSprite + pop af + call z, LoadGhostPic +ELSE call LoadMonFrontSprite +ENDC jr .enemyMonPicReloaded .doEnemyMonAnimation ld b, BANK(AnimationSubstitute) ; BANK(AnimationMinimizeMon) @@ -2913,6 +2944,12 @@ NoMovesLeftText: text_end SwapMovesInMenu: +; Prevent move swapping while transformed +IF DEF(_BUGFIX) + ld a, [wPlayerBattleStatus3] + bit TRANSFORMED, a + jp nz, MoveSelectionMenu +ENDC IF DEF(_DEBUG) ld a, [wFlags_D733] bit BIT_TEST_BATTLE, a @@ -3617,8 +3654,14 @@ CheckPlayerStatusConditions: .MonHurtItselfOrFullyParalysed ld hl, wPlayerBattleStatus1 ld a, [hl] + +IF DEF(_BUGFIX) + ; the original code forgot to clear the invulnerability status of Fly or Dig + and ~((1 << STORING_ENERGY) | (1 << THRASHING_ABOUT) | (1 << CHARGING_UP) | (1 << USING_TRAPPING_MOVE) | (1 << INVULNERABLE)) +ELSE ; clear bide, thrashing, charging up, and trapping moves such as warp (already cleared for confusion damage) and ~((1 << STORING_ENERGY) | (1 << THRASHING_ABOUT) | (1 << CHARGING_UP) | (1 << USING_TRAPPING_MOVE)) +ENDC ld [hl], a ld a, [wPlayerMoveEffect] cp FLY_EFFECT @@ -4793,14 +4836,23 @@ CriticalHitTest: ld c, [hl] ; read move id ld a, [de] bit GETTING_PUMPED, a ; test for focus energy - jr nz, .focusEnergyUsed ; bug: using focus energy causes a shift to the right instead of left, - ; resulting in 1/4 the usual crit chance +; bug: using focus energy causes a shift to the right instead of left, +; resulting in 1/4 the usual crit chance +IF DEF(_BUGFIX) + jr z, .noFocusEnergyUsed sla b ; (effective (base speed/2)*2) + jr c, .guaranteedCriticalHit + sla b ; (effective (base speed/2)*4) + jr c, .guaranteedCriticalHit +ELSE + jr nz, .focusEnergyUsed + sla b ; regular moves become effective (base speed/2)*2 jr nc, .noFocusEnergyUsed ld b, $ff ; cap at 255/256 jr .noFocusEnergyUsed .focusEnergyUsed - srl b + srl b ; focus energy moves become effective (base speed/2)/2 +ENDC .noFocusEnergyUsed ld hl, HighCriticalMoves ; table of high critical hit moves .Loop @@ -4809,23 +4861,48 @@ CriticalHitTest: jr z, .HighCritical ; if so, the move about to be used is a high critical hit ratio move inc a ; move on to the next move, FF terminates loop jr nz, .Loop ; check the next move in HighCriticalMoves +; Fixing the focus energy code reveals that the crit rate would still be capped at 50% +; This shift can then simply be removed in a simpler implementation of fixing focus energy +; Which would also fix the 50% cap +; This also removes the additional 2x difference making high critical hit moves x8 +; Making High Critical Hit Chance Moves and Focus Energy a consistent x4 multiplier +IF !DEF(_BUGFIX) srl b ; /2 for regular move (effective (base speed / 2)) +ENDC jr .SkipHighCritical ; continue as a normal move .HighCritical - sla b ; *2 for high critical hit moves + sla b ; *2 for high critical hit moves - effective (base speed/2)*4)) or effective (base speed/2)*2) if bugs fixed +IF DEF(_BUGFIX) + jr c, .guaranteedCriticalHit +ELSE jr nc, .noCarry ld b, $ff ; cap at 255/256 .noCarry - sla b ; *4 for high critical move (effective (base speed/2)*8)) +ENDC + sla b ; *4 for high critical moves - effective (base speed/2)*8)) or effective (base speed/2)*4) if bugs fixed +IF DEF(_BUGFIX) + jr c, .guaranteedCriticalHit +ELSE jr nc, .SkipHighCritical ld b, $ff +ENDC .SkipHighCritical +; The original code here can "gen 1 miss" a critical hit even when the chance is guaranteed +IF DEF(_BUGFIX) + ld a, b + inc a ; optimization of "cp $ff" + jr z, .guaranteedCriticalHit +ENDC call BattleRandom ; generates a random value, in "a" rlc a rlc a rlc a cp b ; check a against calculated crit rate ret nc ; no critical hit if no borrow +; adding this label in the bugfix code enables several optimizations +IF DEF(_BUGFIX) +.guaranteedCriticalHit +ENDC ld a, $1 ld [wCriticalHitOrOHKO], a ; set critical hit flag ret @@ -5438,6 +5515,24 @@ AdjustDamageForMoveType: ld b, a ld a, [hl] ; a = damage multiplier ldh [hMultiplier], a +; fix the reported type effectiveness of moves used on dual type pokemon +IF DEF(_BUGFIX) + and a ; cp NO_EFFECT + jr z, .gotMultiplier + cp NOT_VERY_EFFECTIVE + jr nz, .nothalf + ld a, [wDamageMultipliers] + and $7f + srl a + jr .gotMultiplier +.nothalf + cp SUPER_EFFECTIVE + jr nz, .gotMultiplier + ld a, [wDamageMultipliers] + and $7f + sla a +.gotMultiplier +ENDC add b ld [wDamageMultipliers], a xor a @@ -5612,7 +5707,14 @@ MoveHitTest: ret nz ; if so, always hit regardless of accuracy/evasion .calcHitChance call CalcHitChance ; scale the move accuracy according to attacker's accuracy and target's evasion +; In the original code, wPlayerMoveAccuracy is not reset each turn before being scaled +; which affects multi turn moves like Rage and Thrash which don't reload the accuracy between turns +; we load explicitly from a separate scaled variable here to fix this +IF DEF(_BUGFIX) + ld a, [wScaledPlayerMoveAccuracy] +ELSE ld a, [wPlayerMoveAccuracy] +ENDC ld b, a ldh a, [hWhoseTurn] and a @@ -5622,6 +5724,12 @@ MoveHitTest: .doAccuracyCheck ; if the random number generated is greater than or equal to the scaled accuracy, the move misses ; note that this means that even the highest accuracy is still just a 255/256 chance, not 100% +; The following snippet is taken from Pokemon Crystal, it fixes the above bug. +IF DEF(_BUGFIX) + ld a, b + cp $FF ; Is the value $FF? + ret z ; If so, we need not calculate, just so we can fix this bug. +ENDC call BattleRandom cp b jr nc, .moveMissed @@ -5647,7 +5755,16 @@ MoveHitTest: ; values for player turn CalcHitChance: +; In the original code, wPlayerMoveAccuracy is not reset each turn before being scaled +; which affects multi turn moves like Rage and Thrash which don't reload the accuracy between turns +; we explicitly reset the scaled accuracy from wPlayerMoveAccuracy each turn here to fix this +IF DEF(_BUGFIX) + ld a, [wPlayerMoveAccuracy] + ld [wScaledPlayerMoveAccuracy], a + ld hl, wScaledPlayerMoveAccuracy +ELSE ld hl, wPlayerMoveAccuracy +ENDC ldh a, [hWhoseTurn] and a ld a, [wPlayerMonAccuracyMod] @@ -6427,12 +6544,20 @@ LoadEnemyMonData: ld a, [wEnemyMonSpecies2] ld [wd11e], a predef IndexToPokedex +; avoid marking a pokemon as seen if it's not identified via the silph scope +IF DEF(_BUGFIX) + call IsGhostBattle + jr z, .noMarkSeen +ENDC ld a, [wd11e] dec a ld c, a ld b, FLAG_SET ld hl, wPokedexSeen predef FlagActionPredef ; mark this mon as seen in the pokedex +IF DEF(_BUGFIX) +.noMarkSeen +ENDC ld hl, wEnemyMonLevel ld de, wEnemyMonUnmodifiedLevel ld bc, 1 + NUM_STATS * 2 @@ -6759,6 +6884,25 @@ ApplyBadgeStatBoosts: ld a, [wObtainedBadges] ld b, a ld hl, wBattleMonAttack +; loop unrolled to fix badge boosts to match in game text +; and the way it was fixed in FRLG +IF DEF(_BUGFIX) + srl b + call c, .applyBoostToStat + ld hl, wBattleMonSpeed + srl b + srl b + call c, .applyBoostToStat + ld hl, wBattleMonDefense + srl b + srl b + call c, .applyBoostToStat + ld hl, wBattleMonSpecial + srl b + srl b + call c, .applyBoostToStat + ret +ELSE ld c, $4 ; the boost is applied for badges whose bit position is even ; the order of boosts matches the order they are laid out in RAM @@ -6775,6 +6919,7 @@ ApplyBadgeStatBoosts: dec c jr nz, .loop ret +ENDC ; multiply stat at hl by 1.125 ; cap stat at MAX_STAT_VALUE diff --git a/engine/battle/effects.asm b/engine/battle/effects.asm index f13d679c1..de09453a9 100644 --- a/engine/battle/effects.asm +++ b/engine/battle/effects.asm @@ -327,7 +327,10 @@ FreezeBurnParalyzeEffect: ld hl, BurnedText jp PrintText .freeze2 -; hyper beam bits aren't reseted for opponent's side +; hyper beam bits aren't reset for the opponent's side +IF DEF(_BUGFIX) + call ClearHyperBeam +ENDC ld a, 1 << FRZ ld [wBattleMonStatus], a ld a, SHAKE_SCREEN_ANIM @@ -528,6 +531,14 @@ UpdateStatDone: pop af call nz, Bankswitch .applyBadgeBoostsAndStatusPenalties +; Prevent reapplication of badge boosts +IF DEF(_BUGFIX) + xor a + ld [wCalculateWhoseStats], a + ldh a, [hWhoseTurn] + and a + call z, CalculateModifiedStats +ENDC ldh a, [hWhoseTurn] and a call z, ApplyBadgeStatBoosts ; whenever the player uses a stat-up move, badge boosts get reapplied again to every stat, @@ -720,6 +731,12 @@ UpdateLoweredStatDone: .ApplyBadgeBoostsAndStatusPenalties ldh a, [hWhoseTurn] and a +; Prevent reapplication of badge boosts +IF DEF(_BUGFIX) + call nz, CalculateModifiedStats + ldh a, [hWhoseTurn] + and a +ENDC call nz, ApplyBadgeStatBoosts ; whenever the player uses a stat-down move, badge boosts get reapplied again to every stat, ; even to those not affected by the stat-up move (will be boosted further) ld hl, MonsStatsFellText diff --git a/engine/battle/init_battle.asm b/engine/battle/init_battle.asm index e7be112cd..47b2be27d 100644 --- a/engine/battle/init_battle.asm +++ b/engine/battle/init_battle.asm @@ -56,7 +56,38 @@ InitBattleCommon: jp z, _InitBattleCommon callabd_ModifyPikachuHappiness PIKAHAPPY_GYMLEADER ; useless since already in bank3d jp _InitBattleCommon - +; fixes for identifying ghosts via entering and leaving menus +IF DEF(_BUGFIX) +LoadGhostPic: + ld hl, wMonHSpriteDim + ld a, $66 + ld [hli], a ; write sprite dimensions + ld bc, GhostPic + ld a, c + ld [hli], a ; write front sprite pointer + ld [hl], b + ld hl, wEnemyMonNick ; set name to "GHOST" + ld a, "G" + ld [hli], a + ld a, "H" + ld [hli], a + ld a, "O" + ld [hli], a + ld a, "S" + ld [hli], a + ld a, "T" + ld [hli], a + ld [hl], "@" + ld a, [wcf91] + push af + ld a, MON_GHOST + ld [wcf91], a + ld de, vFrontPic + call LoadMonFrontSprite ; load ghost sprite + pop af + ld [wcf91], a + ret +ENDC InitWildBattle: ld a, $1 ld [wIsInBattle], a @@ -68,6 +99,10 @@ InitWildBattle: callfar IsGhostBattle jr nz, .isNoGhost .isGhost +; fixes for identifying ghosts via entering and leaving menus +IF DEF(_BUGFIX) + call LoadGhostPic +ELSE ld hl, wMonHSpriteDim ld a, $66 ld [hli], a ; write sprite dimensions @@ -95,6 +130,7 @@ InitWildBattle: call LoadMonFrontSprite ; load ghost sprite pop af ld [wcf91], a +ENDC jr .spriteLoaded .isNoGhost ld de, vFrontPic diff --git a/engine/battle/move_effects/heal.asm b/engine/battle/move_effects/heal.asm index c3ffda657..d5f9f0062 100644 --- a/engine/battle/move_effects/heal.asm +++ b/engine/battle/move_effects/heal.asm @@ -11,13 +11,20 @@ HealEffect_: .healEffect ld b, a ld a, [de] - cp [hl] ; most significant bytes comparison is ignored - ; causes the move to miss if max HP is 255 or 511 points higher than the current HP + cp [hl] inc de inc hl +; most significant bytes comparison is ignored from cp [hl] +; causes the move to miss if max HP is 255 or 511 points higher than the current HP +IF DEF(_BUGFIX) + jr z, .passed +ENDC ld a, [de] sbc [hl] jp z, .failed ; no effect if user's HP is already at its maximum +IF DEF(_BUGFIX) +.passed +ENDC ld a, b cp REST jr nz, .healHP diff --git a/engine/battle/move_effects/substitute.asm b/engine/battle/move_effects/substitute.asm index b1fd8ac28..8966000ee 100644 --- a/engine/battle/move_effects/substitute.asm +++ b/engine/battle/move_effects/substitute.asm @@ -37,7 +37,10 @@ SubstituteEffect_: sbc 0 pop bc jr c, .notEnoughHP ; underflow means user would be left with negative health - ; bug: since it only branches on carry, it will possibly leave user with 0 HP +; Prevent leaving the user at 0 HP by also branching on the zero flag +IF DEF(_BUGFIX) + jr z, .notEnoughHP +ENDC .userHasZeroOrMoreHP ldi [hl], a ; save resulting HP after subtraction into current HP ld [hl], d diff --git a/engine/battle/trainer_ai.asm b/engine/battle/trainer_ai.asm index 41325ce79..0d499f669 100644 --- a/engine/battle/trainer_ai.asm +++ b/engine/battle/trainer_ai.asm @@ -351,10 +351,12 @@ CooltrainerMAI: jp AIUseXAttack CooltrainerFAI: - ; The intended 25% chance to consider switching will not apply. - ; Uncomment the line below to fix this. cp 25 percent + 1 - ; ret nc +; The intended 25% chance to consider switching will not apply. +; Uncomment the line below to fix this. +IF DEF(_BUGFIX) + ret nc +ENDC ld a, 10 call AICheckIfHPBelowFraction jp c, AIUseHyperPotion @@ -558,6 +560,12 @@ AIPrintItemUseAndUpdateHPBar: xor a ld [wHPBarType], a predef UpdateHPBar2 +; fix to update enemy pokemon status HUD when healing items are used +IF DEF(_BUGFIX) + push af + farcall DrawEnemyHUDAndHPBar + pop af +ENDC jp DecrementAICount AISwitchIfEnoughMons: @@ -642,6 +650,12 @@ AICureStatus: ld [wEnemyMonStatus], a ; clear status of active enemy ld hl, wEnemyBattleStatus3 res 0, [hl] +; fix to update enemy pokemon status HUD when healing items are used +IF DEF(_BUGFIX) + push af + farcall DrawEnemyHUDAndHPBar + pop af +ENDC ret AIUseXAccuracy: ; unused diff --git a/engine/events/hidden_objects/vermilion_gym_trash2.asm b/engine/events/hidden_objects/vermilion_gym_trash2.asm index 1bc0590b1..f9a90a5ae 100644 --- a/engine/events/hidden_objects/vermilion_gym_trash2.asm +++ b/engine/events/hidden_objects/vermilion_gym_trash2.asm @@ -32,12 +32,27 @@ TrashCanRandom: call Random swap a cp 1 * $ff / 3 +; the can index needs to be returned in the a register, not b +IF DEF(_BUGFIX) + ld a, 0 +ELSE ld b, 0 +ENDC ret c cp 2 * $ff / 3 +; the can index needs to be returned in the a register, not b +IF DEF(_BUGFIX) + ld a, 1 +ELSE ld b, 1 +ENDC ret c +; the can index needs to be returned in the a register, not b +IF DEF(_BUGFIX) + ld a, 2 +ELSE ld b, 2 +ENDC ret .four diff --git a/engine/items/item_effects.asm b/engine/items/item_effects.asm index c495f991d..30bdc9c21 100644 --- a/engine/items/item_effects.asm +++ b/engine/items/item_effects.asm @@ -488,8 +488,13 @@ ItemUseBall: ld hl, wEnemyBattleStatus3 bit TRANSFORMED, [hl] jr z, .notTransformed +; there's no reason to assume that a transformed pokemon is a ditto +; if a player battles with a ditto with transform against a wild pokemon with mirror move +; it could copy TRANSFORM and then if it uses it be caught as a ditto improperly +IF !DEF(_BUGFIX) ld a, DITTO ld [wEnemyMonSpecies2], a +ENDC jr .skip6 .notTransformed @@ -1008,7 +1013,15 @@ ItemUseMedicine: ld de, wBattleMonStats ld bc, NUM_STATS * 2 call CopyData ; copy party stats to in-battle stat data +; Fix broken effects of curing burn or paralysis on stats +IF DEF(_BUGFIX) + xor a + ld [wCalculateWhoseStats], a + callfar CalculateModifiedStats + callfar ApplyBadgeStatBoosts +ELSE predef DoubleOrHalveSelectedStats +ENDC jp .doneHealing .healHP @@ -1751,6 +1764,11 @@ ItemUsePokedoll: dec a jp nz, ItemUseNotTime ld a, $01 + ; Bugfix for Poke Doll Enabling a Sequence Break in Lavender Tower + ; Marks the result of battles where poke doll is used as a loss +IF DEF(_BUGFIX) + ld [wBattleResult], a +ENDC ld [wEscapedFromBattle], a jp PrintItemUseTextAndRemoveItem diff --git a/engine/math/random.asm b/engine/math/random.asm index c8760157b..3426fb9cb 100644 --- a/engine/math/random.asm +++ b/engine/math/random.asm @@ -1,4 +1,12 @@ Random_:: +IF DEF(_BUGFIX) +; use the more thorough prng to minimize rng correlation effects + call XorshiftRandom + ldh [hRandomAdd], a + call XorshiftRandom + ldh [hRandomSub], a + ret +ELSE ; Generate a random 16-bit value. ldh a, [rDIV] ld b, a @@ -11,3 +19,42 @@ Random_:: sbc b ldh [hRandomSub], a ret +ENDC + +IF DEF(_BUGFIX) +; luckytyphlosion implementation of xorshift prng +; ported from https://github.com/edrosten/8bit_rng +XorshiftRandom: + push bc + ld hl, wRandomSeed + ld a, [hl] ; read in x + ; x << 4 + add a + add a + add a + add a + xor [hl] + ld b, a ; t = x ^ (x << 4) + ld hl, wRandomSeed + 3 + ld a, [hld] ; read in a ; hl = +2 + ld c, [hl] ; read in z ; hl = +2 + ld [hld], a ; z = a ; hl = +1 + ld a, c ; move z to a + ld c, [hl] ; read in y + ld [hld], a ; y = old z + ld [hl], c ; x = y + ld a, [wRandomSeed+2] + ld c, a + ; hl = y + ; vars + ; b contains t + ; a/c contains z + xor b ; z ^ t + srl c ; (z >> 1) + xor c ; z ^ t ^ (z >> 1) + sla b ; (t << 1) + xor b ; z ^ t ^ (z >> 1) ^ (t << 1) + ld [wRandomSeed + 3], a + pop bc + ret +ENDC diff --git a/engine/menus/main_menu.asm b/engine/menus/main_menu.asm index ce0b12c58..f68910434 100644 --- a/engine/menus/main_menu.asm +++ b/engine/menus/main_menu.asm @@ -1,4 +1,13 @@ MainMenu: +; Ensure we initialize wRandomSeed if it isn't carrying over from a previous save +IF DEF(_BUGFIX) + xor a + ld [wRandomSeed], a + ld [wRandomSeed], a + ld [wRandomSeed], a + inc a + ld [wRandomSeed+3], a +ENDC ; Check save file call InitOptions xor a diff --git a/engine/menus/options.asm b/engine/menus/options.asm index e2c02e428..52382db7f 100644 --- a/engine/menus/options.asm +++ b/engine/menus/options.asm @@ -1,4 +1,12 @@ DisplayOptionMenu_: + ; This section fixes the Fast Options glitch + ; The code as written applies any direction button presses done simultaneous with selecting the menu + ; To each option while rendering the menu +IF DEF(_BUGFIX) + call JoypadLowSensitivity + xor a + ldh [hJoy5], a +ENDC call InitOptionsMenu .optionMenuLoop call JoypadLowSensitivity diff --git a/engine/menus/save.asm b/engine/menus/save.asm index 359830d91..50579cf0e 100644 --- a/engine/menus/save.asm +++ b/engine/menus/save.asm @@ -4,6 +4,25 @@ LoadSAV: call ClearScreen call LoadFontTilePatterns call LoadTextBoxTilePatterns +; tell the user the save is corrupt if they turned off the power while saving +; and carry random state through power on/off +IF DEF(_BUGFIX) + call EnableSRAMAndLatchClockData + ld a, $1 + ld [MBC1SRamBank], a + ld a, [sSaveInProgress] + cp 1 + jr z, .badsum + ld a, [sRandomSeed] + ld [wRandomSeed], a + ld a, [sRandomSeed+1] + ld [wRandomSeed+1], a + ld a, [sRandomSeed+2] + ld [wRandomSeed+2], a + ld a, [sRandomSeed+3] + ld [wRandomSeed+3], a + call DisableSRAMAndPrepareClockData +ENDC call LoadSAV0 jr c, .badsum call LoadSAV1 @@ -152,9 +171,40 @@ SaveSAV: and a ret nz .save +; fix the order of text printing so that saving actually happens when the game says it does +; also load a flag into sSaveInProgress to mark if the game was turned off during saving +; and carry random state through power off +IF DEF(_BUGFIX) + ld hl, SavingText + call PrintText + call EnableSRAMAndLatchClockData + ld a, $1 + ld [MBC1SRamBank], a + xor a + inc a + ld [sSaveInProgress], a + ld a, [wRandomSeed] + ld [sRandomSeed], a + ld a, [wRandomSeed+1] + ld [sRandomSeed+1], a + ld a, [wRandomSeed+2] + ld [sRandomSeed+2], a + ld a, [wRandomSeed+3] + ld [sRandomSeed+3], a +ENDC call SaveSAVtoSRAM +; reset the saving in progress flag +IF DEF(_BUGFIX) + call EnableSRAMAndLatchClockData + ld a, $1 + ld [MBC1SRamBank], a + xor a + ld [sSaveInProgress], a + call DisableSRAMAndPrepareClockData +ELSE ld hl, SavingText call PrintText +ENDC ld c, 128 call DelayFrames ld hl, GameSavedText @@ -278,6 +328,10 @@ SAVCheckSum: .loop ld a, [hli] add d +; make the checksum a little more powerful +IF DEF(_BUGFIX) + rrca +ENDC ld d, a dec bc ld a, b diff --git a/engine/movie/splash.asm b/engine/movie/splash.asm index b393d3194..e80fe7da9 100644 --- a/engine/movie/splash.asm +++ b/engine/movie/splash.asm @@ -136,7 +136,12 @@ AnimateShootingStar: ld a, [wMoveDownSmallStarsOAMCount] cp 24 jr z, .next2 - add 6 ; should be 4, but the extra 2 aren't visible on screen +; originally 2 extra stars are set up but only offscreen +IF DEF(_BUGFIX) + add 4 +ELSE + add 6 +ENDC ld [wMoveDownSmallStarsOAMCount], a .next2 call MoveDownSmallStars diff --git a/engine/overworld/clear_variables.asm b/engine/overworld/clear_variables.asm index bbb7c986b..a594c05e0 100644 --- a/engine/overworld/clear_variables.asm +++ b/engine/overworld/clear_variables.asm @@ -17,4 +17,11 @@ ClearVariablesOnEnterMap:: ld hl, wWhichTrade ld bc, wStandingOnWarpPadOrHole - wWhichTrade call FillMemory +; Clear a possible bad game state after Trainer Fly +IF DEF(_BUGFIX) + ld hl, wd730 + set 3, [hl] ; Tells the trainer encounter script to cancel any pending encounters + ld hl, wFlags_0xcd60 + res 0, [hl] ; Clear encountered trainer flag (avoid blocked buttons after a Trainer Fly) +ENDC ret diff --git a/engine/overworld/healing_machine.asm b/engine/overworld/healing_machine.asm index 3bd739b7a..2d7cb2d96 100644 --- a/engine/overworld/healing_machine.asm +++ b/engine/overworld/healing_machine.asm @@ -1,7 +1,12 @@ AnimateHealingMachine: ld de, PokeCenterFlashingMonitorAndHealBall ld hl, vChars0 tile $7c - lb bc, BANK(PokeCenterFlashingMonitorAndHealBall), 3 ; should be 2 +; fix an animation in the healing machine +IF DEF(_BUGFIX) + lb bc, BANK(PokeCenterFlashingMonitorAndHealBall), 2 +ELSE + lb bc, BANK(PokeCenterFlashingMonitorAndHealBall), 3 +ENDC call CopyVideoData ld hl, wUpdateSpritesEnabled ld a, [hl] diff --git a/engine/overworld/movement.asm b/engine/overworld/movement.asm index e6ca87486..818ecfa9f 100644 --- a/engine/overworld/movement.asm +++ b/engine/overworld/movement.asm @@ -580,12 +580,22 @@ CanWalkOntoTile: ld a, [hli] ; x#SPRITESTATEDATA1_YPIXELS add $4 ; align to blocks (Y pos is always 4 pixels off) add d ; add Y delta +; fix the bottom row of the screen being treated as offscreen +IF DEF(_BUGFIX) + cp $81 +ELSE cp $80 ; if value is >$80, the destination is off screen (either $81 or $FF underflow) +ENDC jr nc, .impassable ; don't walk off screen inc l ld a, [hl] ; x#SPRITESTATEDATA1_XPIXELS add e ; add X delta +; fix the rightmost column of the screen being treated as offscreen +IF DEF(_BUGFIX) + cp $91 +ELSE cp $90 ; if value is >$90, the destination is off screen (either $91 or $FF underflow) +ENDC jr nc, .impassable ; don't walk off screen push de push bc diff --git a/engine/overworld/player_animations.asm b/engine/overworld/player_animations.asm index 6f8a5c188..1569da7ba 100644 --- a/engine/overworld/player_animations.asm +++ b/engine/overworld/player_animations.asm @@ -90,6 +90,10 @@ PlayerSpinWhileMovingDown: ld [hli], a ; wPlayerSpinWhileMovingUpOrDownAnimMaxY call GetPlayerTeleportAnimFrameDelay ld [hl], a ; wPlayerSpinWhileMovingUpOrDownAnimFrameDelay +; fix a garbage text character appearing instead of the spinning animation when using escape rope +IF DEF(_BUGFIX) + ld hl, wFacingDirectionList +ENDC jp PlayerSpinWhileMovingUpOrDown @@ -112,6 +116,10 @@ _LeaveMapAnim:: ld [hli], a ; wPlayerSpinWhileMovingUpOrDownAnimMaxY call GetPlayerTeleportAnimFrameDelay ld [hl], a ; wPlayerSpinWhileMovingUpOrDownAnimFrameDelay +; fix a garbage text character appearing instead of the spinning animation when using escape rope +IF DEF(_BUGFIX) + ld hl, wFacingDirectionList +ENDC call PlayerSpinWhileMovingUpOrDown call IsPlayerStandingOnWarpPadOrHole ld a, b @@ -206,6 +214,12 @@ FlyAnimationScreenCoords2: db $F0, $00 LeaveMapThroughHoleAnim: +; reset the music after falling through a hole on a bicycle +IF DEF(_BUGFIX) + ld a, [wLastMusicSoundID] + cp MUSIC_BIKE_RIDING + call z, PlayDefaultMusic +ENDC ld a, $ff ld [wUpdateSpritesEnabled], a ; disable UpdateSprites ; shift upper half of player's sprite down 8 pixels and hide lower half diff --git a/engine/pikachu/pikachu_follow.asm b/engine/pikachu/pikachu_follow.asm index 9575c3415..a35fea830 100644 --- a/engine/pikachu/pikachu_follow.asm +++ b/engine/pikachu/pikachu_follow.asm @@ -1164,13 +1164,34 @@ ClearPikachuFollowCommandBuffer: AppendPikachuFollowCommandToBuffer: ld hl, wPikachuFollowCommandBufferSize - inc [hl] +; Bugfixes for pikawalk +; The game allocates 16 bytes of space for pikachu follow commands +; But the original source has no bounds checking to ensure the buffer size +; stays within the allocated bounds, opening up a buffer overflow exploit +; by walking with pikachu asleep offscreen in the Pewter City Pokemon Center + inc [hl] +IF DEF(_BUGFIX) + push af + ld a, 15 + cp [hl] + jp c, .skipAppending +ENDC ld e, [hl] ld d, 0 ld hl, wPikachuFollowCommandBuffer add hl, de +; restore af from the skip check +IF DEF(_BUGFIX) + pop af +ENDC ld [hl], a ret +; restore af from the skip check and return +IF DEF(_BUGFIX) +.skipAppending + pop af + ret +ENDC RefreshPikachuFollow: call ClearPikachuFollowCommandBuffer diff --git a/engine/slots/slot_machine.asm b/engine/slots/slot_machine.asm index 3918e8793..fb0e1cd1e 100644 --- a/engine/slots/slot_machine.asm +++ b/engine/slots/slot_machine.asm @@ -305,7 +305,12 @@ SlotMachine_StopWheel1Early: .loop ld a, [hli] cp HIGH(SLOTS7) - jr c, .stopWheel ; condition never true +; the original condition is never true, intended to compare against the zero flag +IF DEF(_BUGFIX) + jr z, .stopWheel +ELSE + jr c, .stopWheel +ENDC dec c jr nz, .loop ret @@ -854,7 +859,12 @@ LoadSlotMachineTiles: call DisableLCD ld hl, SlotMachineTiles2 ld de, vChars0 - ld bc, $1c tiles ; should be SlotMachineTiles2End - SlotMachineTiles2, or $18 tiles +; should be SlotMachineTiles2End - SlotMachineTiles2, or $18 tiles +IF DEF(_BUGFIX) + ld bc, SlotMachineTiles2End - SlotMachineTiles2 +ELSE + ld bc, $1c tiles +ENDC ld a, BANK(SlotMachineTiles2) call FarCopyData ld hl, SlotMachineTiles1 @@ -864,7 +874,12 @@ LoadSlotMachineTiles: call FarCopyData ld hl, SlotMachineTiles2 ld de, vChars2 tile $25 - ld bc, $1c tiles ; should be SlotMachineTiles2End - SlotMachineTiles2, or $18 tiles +; should be SlotMachineTiles2End - SlotMachineTiles2, or $18 tiles +IF DEF(_BUGFIX) + ld bc, SlotMachineTiles2End - SlotMachineTiles2 +ELSE + ld bc, $1c tiles +ENDC ld a, BANK(SlotMachineTiles2) call FarCopyData ld hl, SlotMachineMap diff --git a/home/overworld.asm b/home/overworld.asm index 62d0e3b77..8dfa48e7b 100644 --- a/home/overworld.asm +++ b/home/overworld.asm @@ -1329,7 +1329,13 @@ CheckForTilePairCollisions:: jr .retry .currentTileMatchesFirstInPair inc hl +; fix performance issue in collision detection +; the original code can continue to loop unnecessarily after finding a match in the pair +IF DEF(_BUGFIX) + ld a, [hli] +ELSE ld a, [hl] +ENDC cp c jr z, .foundMatch jr .tilePairCollisionLoop diff --git a/home/text_script.asm b/home/text_script.asm index 5e2603206..9212f957b 100644 --- a/home/text_script.asm +++ b/home/text_script.asm @@ -1,6 +1,8 @@ +IF !DEF(_BUGFIX) UnknownText_2812:: ; unreferenced text_far _PokemonText text_end +ENDC ; this function is used to display sign messages, sprite dialog, etc. ; INPUT: [hSpriteIndexOrTextID] = sprite ID or text ID diff --git a/home/trainers.asm b/home/trainers.asm index 468b63f8c..93566cfb3 100644 --- a/home/trainers.asm +++ b/home/trainers.asm @@ -72,10 +72,13 @@ ReadTrainerHeaderInfo:: jr z, .readPointer ; read end battle text cp $a jr nz, .done +; fix the end battle text (2) +IF !DEF(_BUGFIX) ld a, [hli] ; read end battle text (2) but override the result afterwards (XXX why, bug?) ld d, [hl] ld e, a jr .done +ENDC .readPointer ld a, [hli] ld h, [hl] @@ -108,6 +111,7 @@ TalkToTrainer:: call ReadTrainerHeaderInfo ; print before battle text call PrintText ld a, $a +; this is fixed by the bugfix in nonZeroOffset call ReadTrainerHeaderInfo ; (?) does nothing apparently (maybe bug in ReadTrainerHeaderInfo) push de ld a, $8 @@ -143,6 +147,12 @@ ENDC .trainerEngaging ld hl, wFlags_D733 set 3, [hl] +; Part of bugfixes around trainer fly +IF DEF(_BUGFIX) + ld hl, wd730 + res 0, [hl] ; Clear NPC movement flag to avoid softlock if this trainer doesn't move + res 3, [hl] ; Clear Trainer encounter reset flag +ENDC ld [wEmotionBubbleSpriteIndex], a xor a ; EXCLAMATION_BUBBLE ld [wWhichEmotionBubble], a @@ -158,6 +168,12 @@ ENDC ; display the before battle text after the enemy trainer has walked up to the player's sprite DisplayEnemyTrainerTextAndStartBattle:: +; Part of bugfixes around trainer fly +IF DEF(_BUGFIX) + ld a, [wd730] + and $8 + jp nz, ResetButtonPressedAndMapScript ; Trainer Fly happened, abort this script +ENDC ld a, [wd730] and $1 ret nz ; return if the enemy trainer hasn't finished walking to the player's sprite @@ -220,7 +236,15 @@ ResetButtonPressedAndMapScript:: ldh [hJoyHeld], a ldh [hJoyPressed], a ldh [hJoyReleased], a - ld [wCurMapScript], a ; reset battle status + ld [wCurMapScript], a ; reset battle status +; Part of fixes around trainer fly +IF DEF(_BUGFIX) + ld hl, wd730 + res 0, [hl] ; Clear NPC movement flag to avoid potential softlocks + set 3, [hl] ; Set Trainer encounter reset flag to avoid Mew Glitch + ld hl, wFlags_0xcd60 + res 0, [hl] ; player is no longer engaged by any trainer +ENDC ret ; calls TrainerWalkUpToPlayer diff --git a/home/trainers2.asm b/home/trainers2.asm index 78fb64633..b61385bfd 100644 --- a/home/trainers2.asm +++ b/home/trainers2.asm @@ -42,7 +42,9 @@ IsFightingJessieJames:: ld de, JessieJamesPic cp $2e jr c, .dummy +IF !DEF(_BUGFIX) ld de, JessieJamesPic ; possibly meant to add another pic +ENDC .dummy ld hl, wTrainerPicPointer ld a, e diff --git a/home/uncompress.asm b/home/uncompress.asm index 27474f2dc..63c50099f 100644 --- a/home/uncompress.asm +++ b/home/uncompress.asm @@ -31,14 +31,30 @@ _UncompressSpriteData:: ld [wSpriteLoadFlags], a call ReadNextInputByte ; first byte of input determines sprite width (high nybble) and height (low nybble) in tiles (8x8 pixels) ld b, a +; fix glitch sprites corrupting SRAM +IF DEF(_BUGFIX) + and $7 + jr nz, .skip1 + inc a +.skip1 +ELSE and $f +ENDC add a add a add a ld [wSpriteHeight], a ld a, b swap a +; fix glitch sprites corrupting SRAM +IF DEF(_BUGFIX) + and $7 + jr nz, .skip2 + inc a +.skip2 +ELSE and $f +ENDC add a add a add a diff --git a/home/yes_no.asm b/home/yes_no.asm index 3f5a5a45b..1a8c2e3ca 100644 --- a/home/yes_no.asm +++ b/home/yes_no.asm @@ -5,11 +5,14 @@ YesNoChoice:: call InitYesNoTextBoxParameters jr DisplayYesNoChoice +; removed in bugfix patch to make space for trainer fly glitch fixes +IF !DEF(_BUGFIX) TwoOptionMenu:: ; unreferenced ld a, TWO_OPTION_MENU ld [wTextBoxID], a call InitYesNoTextBoxParameters jp DisplayTextBoxID +ENDC InitYesNoTextBoxParameters:: xor a ; YES_NO_MENU @@ -26,12 +29,14 @@ YesNoChoicePokeCenter:: lb bc, 8, 12 jr DisplayYesNoChoice +IF !DEF(_BUGFIX) WideYesNoChoice:: ; unused call SaveScreenTilesToBuffer1 ld a, WIDE_YES_NO_MENU ld [wTwoOptionMenuID], a hlcoord 12, 7 lb bc, 8, 13 +ENDC DisplayYesNoChoice:: ld a, TWO_OPTION_MENU diff --git a/pokeyellow-bugfix-romhack.ips b/pokeyellow-bugfix-romhack.ips new file mode 100644 index 000000000..2baa8ac3c Binary files /dev/null and b/pokeyellow-bugfix-romhack.ips differ diff --git a/ram/sram.asm b/ram/sram.asm index 6cb453711..583e9cc10 100644 --- a/ram/sram.asm +++ b/ram/sram.asm @@ -22,7 +22,14 @@ sCurBoxData:: ds wBoxDataEnd - wBoxDataStart sTileAnimations:: db sGameDataEnd:: sMainDataCheckSum:: db - +; adding this variable allows us to track whether the user turned off the power while saving +IF DEF(_BUGFIX) +sSaveInProgress:: db +sRandomSeed:: db + + ds 3 + +ENDC ; The PC boxes will not fit into one SRAM bank, ; so they use multiple SECTIONs diff --git a/ram/wram.asm b/ram/wram.asm index dbe20a463..cbb856dbe 100644 --- a/ram/wram.asm +++ b/ram/wram.asm @@ -1205,9 +1205,19 @@ ENDU wPartyMenuHPBarColors:: ds PARTY_LENGTH wStatusScreenHPBarColor:: db +IF DEF(_BUGFIX) +wRandomSeed:: db + + ds 5 + +wScaledPlayerMoveAccuracy:: db + +ELSE ds 7 +ENDC + wCopyingSGBTileData:: wWhichPartyMenuHPBar:: wPalPacket:: diff --git a/scripts/PokemonTower7F.asm b/scripts/PokemonTower7F.asm index c9da74f76..218c1e5a2 100644 --- a/scripts/PokemonTower7F.asm +++ b/scripts/PokemonTower7F.asm @@ -246,6 +246,11 @@ PokemonTower7Script11: ld [wDestinationWarpID], a ld a, LAVENDER_TOWN ld [wLastMap], a +; make it possible to leave mr fuji's house directly after warping +IF DEF(_BUGFIX) + ld hl, wd736 + set 2, [hl] +ENDC ld hl, wd72d set 3, [hl] ld a, $0 diff --git a/scripts/Route12Gate2F.asm b/scripts/Route12Gate2F.asm index 2174fba8b..3e9cc89e1 100644 --- a/scripts/Route12Gate2F.asm +++ b/scripts/Route12Gate2F.asm @@ -68,6 +68,12 @@ GateUpstairsScript_PrintIfFacingUp: ld a, [wSpritePlayerStateData1FacingDirection] cp SPRITE_FACING_UP jr z, .up +; fix the route 12 gate binoculars +IF DEF(_BUGFIX) + ld hl, TVWrongSideText +.up + call PrintText +ELSE ld a, TRUE jr .done .up @@ -75,4 +81,5 @@ GateUpstairsScript_PrintIfFacingUp: xor a .done ld [wDoNotWaitForButtonPressAfterDisplayingText], a +ENDC jp TextScriptEnd diff --git a/scripts/Route17.asm b/scripts/Route17.asm index 526b25763..05b214dbe 100644 --- a/scripts/Route17.asm +++ b/scripts/Route17.asm @@ -29,6 +29,10 @@ Route17_TextPointers: dw Route17Text14 dw Route17Text15 dw Route17Text16 +; fix the sign at Route 16 showing Celadon <-> Fuchsia when read from the front +IF DEF(_BUGFIX) + dw Route17Text17 +ENDC Route17TrainerHeaders: def_trainers @@ -257,3 +261,9 @@ Route17Text15: Route17Text16: text_far _Route17Text16 text_end +; fix the sign at Route 16 showing Celadon <-> Fuchsia when read from the front +IF DEF(_BUGFIX) +Route17Text17: + text_far _Route16Text9 + text_end +ENDC