diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5845e58b..ab6c8163 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: # os & python versions strategy: matrix: - os-name: [ ubuntu-latest, ubuntu-18.04, macOS-latest, windows-latest ] + os-name: [ ubuntu-latest, ubuntu-20.04, macOS-latest, windows-latest ] python-version: [ 3.9 ] # needs: [ install-test ] steps: @@ -110,7 +110,7 @@ jobs: strategy: matrix: # install/release on not bionic - os-name: [ ubuntu-latest, ubuntu-18.04, macOS-latest, windows-latest ] + os-name: [ ubuntu-latest, ubuntu-20.04, macOS-latest, windows-latest ] python-version: [ 3.9 ] needs: [ install-build ] diff --git a/BaseClasses.py b/BaseClasses.py index 0c014816..cf0432a5 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -744,7 +744,7 @@ class CollectionState(object): @staticmethod def valid_crystal(door, new_crystal_state): return (not door.crystal or door.crystal == CrystalBarrier.Either or new_crystal_state == CrystalBarrier.Either - or new_crystal_state == door.crystal) + or new_crystal_state == door.crystal or door.alternative_crystal_rule) def check_key_doors_in_dungeons(self, rrp, player): for dungeon_name, checklist in self.dungeons_to_check[player].items(): @@ -2084,6 +2084,7 @@ class Door(object): self.bigKey = False # There's a big key door on this side self.ugly = False # Indicates that it can't be seen from the front (e.g. back of a big key door) self.crystal = CrystalBarrier.Null # How your crystal state changes if you use this door + self.alternative_crystal_rule = False self.req_event = None # if a dungeon event is required for this door - swamp palace mostly self.controller = None self.dependents = [] @@ -3716,3 +3717,4 @@ class KeyRuleType(FastEnum): WorstCase = 0 AllowSmall = 1 Lock = 2 + CrystalAlternative = 3 diff --git a/CHANGELOG.md b/CHANGELOG.md index be04e335..ae85449f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.4.0.1 +- \~Merged in DR v1.4.1.10~ +- Fixed issue with bonk items for MW players +- Fixed fake world issues in Glitched modes +- Fixed issue with Flute getting canceled in OWR Layout modes +- Various GFX Fixes + ## 0.4.0.0 - Fully merged big base ROM changes from upstream, including FastROM - \~Merged up to date with DR v1.4.1.8~ diff --git a/DoorShuffle.py b/DoorShuffle.py index 905d65af..9ca2227a 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -20,7 +20,7 @@ from DungeonGenerator import create_dungeon_builders, split_dungeon_builder, sim from DungeonGenerator import dungeon_portals, dungeon_drops, connect_doors, count_reserved_locations from DungeonGenerator import valid_region_to_explore from KeyDoorShuffle import analyze_dungeon, build_key_layout, validate_key_layout, determine_prize_lock -from KeyDoorShuffle import validate_bk_layout +from KeyDoorShuffle import validate_bk_layout, DoorRules from Utils import ncr, kth_combination @@ -264,7 +264,7 @@ def vanilla_key_logic(world, player): log_key_logic(builder.name, key_layout.key_logic) # special adjustments for vanilla if world.keyshuffle[player] != 'universal': - if world.mode[player] != 'standard' and world.dropshuffle[player] == 'none' : + if world.mode[player] != 'standard' and world.dropshuffle[player] == 'none': # adjust hc doors def adjust_hc_door(door_rule): if door_rule.new_rules[KeyRuleType.WorstCase] == 3: @@ -280,9 +280,28 @@ def vanilla_key_logic(world, player): if pod_front.new_rules[KeyRuleType.WorstCase] == 6: pod_front.new_rules[KeyRuleType.WorstCase] = 1 pod_front.small_key_num = 1 + # adjust mire key logic - this currently cannot be done dynamically + create_alternative_door_rules('Mire Hub Upper Blue Barrier', 2, 'Misery Mire', world, player) + create_alternative_door_rules('Mire Hub Lower Blue Barrier', 2, 'Misery Mire', world, player) + create_alternative_door_rules('Mire Hub Right Blue Barrier', 2, 'Misery Mire', world, player) + create_alternative_door_rules('Mire Hub Top Blue Barrier', 2, 'Misery Mire', world, player) + create_alternative_door_rules('Mire Hub Switch Blue Barrier N', 2, 'Misery Mire', world, player) + create_alternative_door_rules('Mire Hub Switch Blue Barrier S', 2, 'Misery Mire', world, player) + create_alternative_door_rules('Mire Map Spot Blue Barrier', 2, 'Misery Mire', world, player) + create_alternative_door_rules('Mire Map Spike Side Blue Barrier', 2, 'Misery Mire', world, player) + create_alternative_door_rules('Mire Crystal Dead End Left Barrier', 2, 'Misery Mire', world, player) + create_alternative_door_rules('Mire Crystal Dead End Right Barrier', 2, 'Misery Mire', world, player) # gt logic? I'm unsure it needs adjusting +def create_alternative_door_rules(door, amount, dungeon, world, player): + rules = DoorRules(0, True) + world.key_logic[player][dungeon].door_rules[door] = rules + rules.new_rules[KeyRuleType.CrystalAlternative] = amount + world.get_door(door, player).alternative_crystal_rule = True + + + def validate_vanilla_reservation(dungeon, world, player): return validate_key_layout(world.key_layout[player][dungeon.name], world, player) diff --git a/Items.py b/Items.py index a637983f..e9a056b5 100644 --- a/Items.py +++ b/Items.py @@ -61,8 +61,8 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche 'Progressive Glove': (True, False, None, 0x61, 150, 'A way to lift\nheavier things', 'and the lift upgrade', 'body-building kid', 'some glove for sale', 'fungus for gloves', 'body-building boy lifts again', 'a Glove'), 'Silver Arrows': (True, False, None, 0x58, 100, 'Do you fancy\nsilver tipped\narrows?', 'and the ganonsbane', 'ganon-killing kid', 'ganon doom for sale', 'fungus for pork', 'archer boy shines again', 'the Silver Arrows'), 'Green Pendant': (True, False, 'Crystal', [0x04, 0x38, 0x62, 0x00, 0x69, 0x37, 0x08], 999, None, None, None, None, None, None, None), - 'Red Pendant': (True, False, 'Crystal', [0x02, 0x32, 0x60, 0x00, 0x69, 0x38, 0x09], 999, None, None, None, None, None, None, None), - 'Blue Pendant': (True, False, 'Crystal', [0x01, 0x34, 0x60, 0x00, 0x69, 0x39, 0x0a], 999, None, None, None, None, None, None, None), + 'Blue Pendant': (True, False, 'Crystal', [0x02, 0x34, 0x60, 0x00, 0x69, 0x39, 0x09], 999, None, None, None, None, None, None, None), + 'Red Pendant': (True, False, 'Crystal', [0x01, 0x32, 0x60, 0x00, 0x69, 0x38, 0x0a], 999, None, None, None, None, None, None, None), 'Triforce': (True, False, None, 0x6A, 777, '\n YOU WIN!', 'and the triforce', 'victorious kid', 'victory for sale', 'fungus for the win', 'greedy boy wins game again', 'the Triforce'), 'Power Star': (True, False, None, 0x6B, 100, 'A small victory', 'and the power star', 'star-struck kid', 'star for sale', 'see stars with shroom', 'mario powers up again', 'a Power Star'), 'Triforce Piece': (True, False, None, 0x6C, 100, 'A small victory', 'and the thirdforce', 'triangular kid', 'triangle for sale', 'fungus for triangle', 'wise boy has triangle again', 'a Triforce piece'), diff --git a/Main.py b/Main.py index 1d32b778..89f10563 100644 --- a/Main.py +++ b/Main.py @@ -7,6 +7,7 @@ import RaceRandom as random import string import time import zlib +import base64 from BaseClasses import World, CollectionState, Item, Region, Location, Shop, Entrance, Settings from Bosses import place_bosses @@ -40,7 +41,7 @@ from source.enemizer.DamageTables import DamageTable from source.enemizer.Enemizer import randomize_enemies from source.rom.DataTables import init_data_tables -version_number = '1.4.1.8' +version_number = '1.4.1.10' version_branch = '-u' __version__ = f'{version_number}{version_branch}' @@ -328,6 +329,10 @@ def main(args, seed=None, fish=None): if args.jsonout: jsonout[f'patch_t{team}_p{player}'] = rom.patches + if args.bps: + localRom = LocalRom.fromJsonRom(rom, args.rom) + patch = create_bps_from_data(LocalRom(args.rom, patch=False).buffer, localRom.buffer) + jsonout[f'bps_t{team}_p{player}'] = base64.b64encode(patch.binary_ba).decode() else: outfilepname = f'_T{team+1}' if world.teams > 1 else '' if world.players > 1: diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 86bd8845..9cb84fb3 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -8,7 +8,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.4.0.0' +version_number = '0.4.0.1' # branch indicator is intentionally different across branches version_branch = '' diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c7e37651..8d57d657 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -141,6 +141,19 @@ These are now independent of retro mode and have three options: None, Random, an # Patch Notes +* 1.4.1.10u + * Vanilla key logic: Fix for vanilla layout Misery Mire which allows more complex key logic. Locations blocked by crystal switch access are only locked by 2 keys thanks to that being the minimum in Mire to reach one of two crystal switches. + * Autotracking: Fix for chest turn counter with chest containing multiworld items (Thanks Hiimcody) + * Enemizer: Enemy bans + * Rom: Code prettification and fixing byte designations by Codemann + * Support added for BPS patches via jsonout setting (Thanks Veetorp!) +* 1.4.1.9u + * Enemy Drop Underworld: Changed enemy drop indicator to not require compass + * Experimental: Moved dark world bunny spawns out of experimental. (It is now always on) + * Fix: Red/Blue pendants were swapped for autotracking. (Thanks Muffins!) + * Fix: Red square sometimes wasn't blinking + * Updated tournament winners + * Enemizer: Enemy bans * 1.4.1.8u * HUD: New dungeon indicators based on common abbreviations * OWG+HMG: EG is allowed to be armed diff --git a/Rom.py b/Rom.py index b6a39375..f12c1a72 100644 --- a/Rom.py +++ b/Rom.py @@ -43,7 +43,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '168c7d6e330a134e7565baedab79aa15' +RANDOMIZERBASEHASH = 'ddbecd34e58b7fdf6bed48114b3124d5' class JsonRom(object): @@ -631,7 +631,7 @@ def patch_rom(world, rom, player, team, is_mystery=False): from OverworldShuffle import can_reach_smith if not can_reach_smith(world, player): - rom.write_byte(0x18005d, 0x01) # patch for deleting smith on S+Q + rom.write_byte(0x180043, 0x01) # patch for deleting smith on S+Q # patch entrance/exits/holes for region in world.regions: @@ -713,8 +713,7 @@ def patch_rom(world, rom, player, team, is_mystery=False): rom.write_bytes(0xfb1fc, [0xc8, 0x9d, 0x69, 0xb4, 0xac, 0x5d]) if world.standardize_palettes[player] == 'original': dr_flags |= DROptions.OriginalPalettes - if world.experimental[player]: - dr_flags |= DROptions.DarkWorld_Spawns + dr_flags |= DROptions.DarkWorld_Spawns # no longer experimental if world.logic[player] not in ['owglitches', 'hybridglitches', 'nologic']: dr_flags |= DROptions.Fix_EG if world.door_type_mode[player] in ['big', 'all', 'chaos']: @@ -1217,7 +1216,7 @@ def patch_rom(world, rom, player, team, is_mystery=False): rom.initial_sram.set_starting_equipment(world, player) rom.write_byte(0x18004A, 0x00 if world.mode[player] != 'inverted' else 0x01) # Inverted mode - rom.write_byte(0x180043, 0x00) # Hammer always breaks barrier + rom.write_byte(0x18005D, 0x00) # Hammer always breaks barrier rom.write_byte(0x02AF79, 0xD0 if world.mode[player] != 'inverted' else 0xF0) # vortexes: Normal (D0=light to dark, F0=dark to light, 42 = both) rom.write_byte(0x03A943, 0xD0 if world.mode[player] != 'inverted' else 0xF0) # Mirror: Normal (D0=Dark to Light, F0=light to dark, 42 = both) rom.write_byte(0x03A96D, 0xF0 if world.mode[player] != 'inverted' else 0xD0) # Residual Portal: Normal (F0= Light Side, D0=Dark Side, 42 = both (Darth Vader)) diff --git a/Rules.py b/Rules.py index c7a9d706..27075c6f 100644 --- a/Rules.py +++ b/Rules.py @@ -1570,6 +1570,7 @@ kill_chests = { + def add_connection(parent_name, target_name, entrance_name, world, player): parent = world.get_region(parent_name, player) target = world.get_region(target_name, player) @@ -2026,10 +2027,13 @@ def add_key_logic_rules(world, player): for d_name, d_logic in key_logic.items(): for door_name, rule in d_logic.door_rules.items(): door_entrance = world.get_entrance(door_name, player) - add_rule(door_entrance, eval_func(door_name, d_name, player)) - if door_entrance.door.dependents: - for dep in door_entrance.door.dependents: - add_rule(dep.entrance, eval_func(door_name, d_name, player)) + if not door_entrance.door.smallKey and door_entrance.door.crystal == CrystalBarrier.Blue: + add_rule(door_entrance, eval_alternative_crystal(door_name, d_name, player), 'or') + else: + add_rule(door_entrance, eval_func(door_name, d_name, player)) + if door_entrance.door.dependents: + for dep in door_entrance.door.dependents: + add_rule(dep.entrance, eval_func(door_name, d_name, player)) for location in d_logic.bk_restricted: if not location.forced_item: forbid_item(location, d_logic.bk_name, player) @@ -2121,6 +2125,15 @@ def eval_small_key_door_strict_main(state, door_name, dungeon, player): return state.has_sm_key_strict(key_layout.key_logic.small_key_name, player, number) +def eval_alternative_crystal_main(state, door_name, dungeon, player): + key_logic = state.world.key_logic[player][dungeon] + door_rule = key_logic.door_rules[door_name] + for ruleType, number in door_rule.new_rules.items(): + if ruleType == KeyRuleType.CrystalAlternative: + return state.has_sm_key(key_logic.small_key_name, player, number) + return False + + def eval_small_key_door(door_name, dungeon, player): return lambda state: eval_small_key_door_main(state, door_name, dungeon, player) @@ -2133,6 +2146,10 @@ def eval_small_key_door_strict(door_name, dungeon, player): return lambda state: eval_small_key_door_strict_main(state, door_name, dungeon, player) +def eval_alternative_crystal(door_name, dungeon, player): + return lambda state: eval_alternative_crystal_main(state, door_name, dungeon, player) + + def allow_big_key_in_big_chest(bk_name, player): return lambda state, item: item.name == bk_name and item.player == player diff --git a/Text.py b/Text.py index 885af7cc..996f4483 100644 --- a/Text.py +++ b/Text.py @@ -125,7 +125,7 @@ Triforce_texts = [ " You get one\n wish. Choose\n wisely, hero!", " Can you please\n break us three\n up? Thanks.", " Pick us up\n before we\n get dizzy!", - " Thank you,\n Mikey. You’re\n 2 minutes late", + " Thank you,\n Mikey. You're\n 2 minutes late", " This was a\n 7000 series\n train.", " I'd buy\n that for\n a rupee!", " Did you like\n that bow\n placement?", @@ -2027,6 +2027,8 @@ class TextTable(object): text['ganon_phase_3_alt'] = CompressedTextMapper.convert("Got wax in your ears? I cannot die!") # 190 text['sign_east_death_mountain_bridge'] = CompressedTextMapper.convert("Glitched\ntournament\nwinners\n{HARP}\n" + "~~~HMG 2023~~~\ntam\n\n" + "~~~No Logic 2022~~~\nChexhuman\n\n" "~~~HMG 2021~~~\nKrithel\n\n" "~~~OWG 2019~~~\nGlan\n\n" "~~~OWG 2018~~~\nChristosOwen\nthe numpty") diff --git a/asm/owrando.asm b/asm/owrando.asm index ee1afb53..1e91896a 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -43,6 +43,9 @@ Overworld_LoadSpecialOverworld_RoomId: org $84E8B4 Overworld_LoadSpecialOverworld: +org $84E96A +JSL OWSpecialReturnTriggerClear + org $82A9DA JSL OWSkipPalettes BCC OverworldHandleTransitions_change_palettes : NOP #4 @@ -151,8 +154,8 @@ jsl OWWorldCheck16 : nop org $9bed95 ; < ? - palettes.asm:748 () jsl OWWorldCheck16 : nop -org $82b16e ; AND #$3F : ORA 7EF3CA -and #$7f : eor #$40 : nop #2 +org $82B16C ; LDA $8A : AND #$3F : ORA 7EF3CA +JSL OWApplyWorld : BRA + : NOP #2 : + org $89C3C4 jsl OWBonkDropPrepSprite : nop #2 @@ -225,6 +228,17 @@ OWMapWorldCheck16: .return rtl } +OWApplyWorld: +{ + LDX.b OverworldIndex + + .fromScreen + LDA.l OWTileWorldAssoc,X : CMP.l CurrentWorld : BEQ .keepWorld ; if dest screen mismatches the current world + TXA : EOR.b #$40 : RTL + + .keepWorld + TXA : RTL +} OWWhirlpoolUpdate: { @@ -290,7 +304,7 @@ OWMirrorSpriteSkipDraw: sec : rtl .vanilla - LDA.w $0FC6 : CMP.b #$03 ; what we wrote over + LDA.w GfxChrHalfSlotVerify : CMP.b #$03 ; what we wrote over RTL } OWLightWorldOrCrossed: @@ -322,7 +336,7 @@ OWFluteCancel2: } OWSmithAccept: { - lda FollowerIndicator : cmp.b #$07 : beq + + lda.l FollowerIndicator : cmp.b #$07 : beq + cmp.b #$08 : beq + clc : rtl + sec : rtl @@ -359,7 +373,7 @@ LoadMapDarkOrMixed: CMP.b #!FLAG_OW_MIXED : REP #$30 : BEQ .mixed LDX.w #$03FE ; draw vanilla Dark World (what we wrote over) .copy_next - LDA.w WorldMap_DarkWorldTilemap,X : STA.w $1000,X + LDA.w WorldMap_DarkWorldTilemap,X : STA.w GFXStripes,X DEX : DEX : BPL .copy_next BRL .end .mixed @@ -526,7 +540,7 @@ OWBonkDrops: ; JSLSpriteSFX_QueueSFX3WithPan .load_item_and_mw - LDA 3,S : TAX : INX : LDA.w OWBonkPrizeData,X + LDA.b 3,S : TAX : INX : LDA.w OWBonkPrizeData,X PHA : INX : LDA.w OWBonkPrizeData,X : BEQ + ; multiworld item DEX : PLA ; A = item id; X = row + 3 @@ -579,11 +593,11 @@ OWBonkDrops: PLA : BNE + ; S = FlagBitmask, X (row + 2) TYX : JSL Sprite_IsOnscreen : BCC + LDA.b IndoorsFlag : BEQ ++ - LDA.l RoomDataWRAM[$0120].high : ORA 1,S : STA.l RoomDataWRAM[$0120].high - LDA.w $0400 : ORA 1,S : STA.w $0400 + LDA.l RoomDataWRAM[$0120].high : ORA.b 1,S : STA.l RoomDataWRAM[$0120].high + LDA.w $0400 : ORA.b 1,S : STA.w $0400 BRA .increment_collection ++ - LDX.b OverworldIndex : LDA.l OverworldEventDataWRAM,X : ORA 1,S : STA.l OverworldEventDataWRAM,X + LDX.b OverworldIndex : LDA.l OverworldEventDataWRAM,X : ORA.b 1,S : STA.l OverworldEventDataWRAM,X .increment_collection REP #$20 @@ -623,10 +637,13 @@ OWBonkDrops: ; sets bitmask flag, uses free RAM PLA : STA.w SpriteSpawnStep,Y ; S = X (row + 2) + ; sets MW player + PLX : INX : INX + LDA.w OWBonkPrizeData,X : STA.w SprItemMWPlayer,Y ; determines the initial spawn point of item - PLX : INX : INX : INX + INX LDA.w SpritePosYLow,Y : SEC : SBC.w OWBonkPrizeData,X : STA.w SpritePosYLow,Y - LDA.w SpritePosYHigh,Y : SBC #$00 : STA.w SpritePosYHigh,Y + LDA.w SpritePosYHigh,Y : SBC.b #$00 : STA.w SpritePosYHigh,Y BRA .return+2 @@ -661,7 +678,7 @@ OWBonkDropCollected: LDA.l RoomDataWRAM[$0120].high : AND.b 3,S : BEQ .return ; S = Collected, FlagBitmask, X (row + 2) SEC : RTS + - LDX.b OverworldIndex : LDA.l OverworldEventDataWRAM,X : AND 3,S : BEQ .return ; S = Collected, FlagBitmask, X (row + 2) + LDX.b OverworldIndex : LDA.l OverworldEventDataWRAM,X : AND.b 3,S : BEQ .return ; S = Collected, FlagBitmask, X (row + 2) SEC : RTS .return @@ -744,8 +761,8 @@ OWDetectSpecialTransition: OWEdgeTransition: { LDA.l OWMode : ORA.l OWMode+1 : BEQ .unshuffled - LDY.w RandoOverworldTargetEdge : CPY.b #$7F - BEQ .unshuffled + LDY.w RandoOverworldTargetEdge : STZ.w RandoOverworldTargetEdge + CPY.b #$7F : BEQ .unshuffled REP #$10 LDX.w RandoOverworldEdgeAddr PHB : PHK : PLB @@ -757,8 +774,7 @@ OWEdgeTransition: .unshuffled LDA.l Overworld_ActualScreenID,X : ORA.l CurrentWorld ; what we wrote over TAX : LDA.l OWMode+1 : AND.b #!FLAG_OW_MIXED : BEQ .vanilla - LDA.l OWTileWorldAssoc,X : CMP.l CurrentWorld : BEQ .vanilla ; if dest screen mismatches the current world - TXA : EOR #$40 : RTL + JML OWApplyWorld_fromScreen .vanilla TXA : RTL @@ -794,18 +810,18 @@ OWShuffle: ldx.b OverworldIndex : lda.l OWTileWorldAssoc,X : eor.l CurrentWorld : beq + ; fake world, will treat this OW area as opposite world txa : eor.b #$40 : tax - + txa : and #$40 : !add.w OverworldSlotPosition : rep #$30 : and #$00ff : asl #3 + + txa : and.b #$40 : !ADD.w OverworldSlotPosition : rep #$30 : and.w #$00ff : asl #3 - adc 1,S : tax + adc.b 1,S : tax asl.w OverworldSlotPosition : pla ;x = offset to edgeoffsets table - sep #$20 : lda.l OWEdgeOffsets,x : and #$ff : beq .noTransition : pha ;get number of transitions + sep #$20 : lda.l OWEdgeOffsets,x : and.b #$ff : beq .noTransition : pha ;get number of transitions ;s1 = number of transitions left to check inx : lda.l OWEdgeOffsets,x ;record id of first transition in table ;multiply ^ by 16, 16bytes per record - sta.w CPUMULTA : lda #16 : sta.w CPUMULTB ;wait 8 cycles + sta.w CPUMULTA : lda.b #16 : sta.w CPUMULTB ;wait 8 cycles pla ;a = number of trans rep #$20 and.w #$00ff @@ -814,7 +830,7 @@ OWShuffle: .nextTransition pha jsr OWSearchTransition_entry : bcs .newDestination - txa : !add.w #$0010 : tax + txa : !ADD.w #$0010 : tax pla : dec : bne .nextTransition : bra .noTransition .newDestination @@ -836,8 +852,8 @@ OWSearchTransition: ;A-16 XY-16 lda.w TransitionDirection : bne + ;north lda.l OWNorthEdges,x : dec - cmp.b LinkPosX : !bge .exitloop - lda.l OWNorthEdges+2,x : cmp.b LinkPosX : !blt .exitloop + cmp.b LinkPosX : !BGE .exitloop + lda.l OWNorthEdges+2,x : cmp.b LinkPosX : !BLT .exitloop ;MATCH lda.l OWNorthEdges+14,x : tay ;y = record id of dest lda.l OWNorthEdges+12,x ;a = current terrain @@ -845,8 +861,8 @@ OWSearchTransition: bra .matchfound + dec : bne + ;south lda.l OWSouthEdges,x : dec - cmp.b LinkPosX : !bge .exitloop - lda.l OWSouthEdges+2,x : cmp.b LinkPosX : !blt .exitloop + cmp.b LinkPosX : !BGE .exitloop + lda.l OWSouthEdges+2,x : cmp.b LinkPosX : !BLT .exitloop ;MATCH lda.l OWSouthEdges+14,x : tay ;y = record id of dest lda.l OWSouthEdges+12,x ;a = current terrain @@ -854,16 +870,16 @@ OWSearchTransition: bra .matchfound + dec : bne + ; west lda.l OWWestEdges,x : dec - cmp.b LinkPosY : !bge .exitloop - lda.l OWWestEdges+2,x : cmp.b LinkPosY : !blt .exitloop + cmp.b LinkPosY : !BGE .exitloop + lda.l OWWestEdges+2,x : cmp.b LinkPosY : !BLT .exitloop ;MATCH lda.l OWWestEdges+14,x : tay ;y = record id of dest lda.l OWWestEdges+12,x ;a = current terrain ldx.w #OWEastEdges ;x = address of table bra .matchfound + lda.l OWEastEdges,x : dec ;east - cmp.b LinkPosY : !bge .exitloop - lda.l OWEastEdges+2,x : cmp.b LinkPosY : !blt .exitloop + cmp.b LinkPosY : !BGE .exitloop + lda.l OWEastEdges+2,x : cmp.b LinkPosY : !BLT .exitloop ;MATCH lda.l OWEastEdges+14,x : tay ;y = record id of dest lda.l OWEastEdges+12,x ;a = current terrain @@ -877,7 +893,7 @@ OWSearchTransition: OWNewDestination: { tya : sta.w CPUMULTA : lda.b #16 : sta.w CPUMULTB ;wait 8 cycles - rep #$20 : txa : nop : !add.w CPUPRODUCT : tax ;a = offset to dest record + rep #$20 : txa : nop : !ADD.w CPUPRODUCT : tax ;a = offset to dest record lda.w $0008,x : sta.b Scrap04 ;save dest OW slot/ID ldy.b LinkPosY : lda.w TransitionDirection : dec #2 : bpl + : ldy.b LinkPosX : + sty.b Scrap06 @@ -888,21 +904,21 @@ OWNewDestination: LDA.l OWMode : AND.w #$0007 : BEQ .noLayoutShuffle ;temporary fix until VRAM issues are solved lda.w $0006,x : sta.b Scrap06 ;set coord lda.w $000a,x : sta.b OverworldMap16Buffer ;VRAM - tya : and.w #$01ff : cmp.b 3,s : !blt .adjustMainAxis - dec : cmp.b 1,s : !bge .adjustMainAxis - inc : pha : lda.b Scrap06 : and.w #$fe00 : !add.b 1,s : sta.b Scrap06 : pla + tya : and.w #$01ff : cmp.b 3,s : !BLT .adjustMainAxis + dec : cmp.b 1,s : !BGE .adjustMainAxis + inc : pha : lda.b Scrap06 : and.w #$fe00 : !ADD.b 1,s : sta.b Scrap06 : pla ; adjust and set other VRAM addresses - lda.w $0006,x : pha : lda.b Scrap06 : !sub 1,s + lda.w $0006,x : pha : lda.b Scrap06 : !SUB 1,s jsl DivideByTwoPreserveSign : jsl DivideByTwoPreserveSign : jsl DivideByTwoPreserveSign : jsl DivideByTwoPreserveSign : pha ; number of tiles lda.w TransitionDirection : dec #2 : bmi + pla : pea.w $0000 : bra ++ ;pla : asl #7 : pha : bra ++ ; y-axis shifts VRAM by increments of 0x80 (disabled for now) + pla : asl : pha ; x-axis shifts VRAM by increments of 0x02 - ++ lda.b OverworldMap16Buffer : !add 1,s : sta.b OverworldMap16Buffer : pla : pla + ++ lda.b OverworldMap16Buffer : !ADD.b 1,s : sta.b OverworldMap16Buffer : pla : pla .adjustMainAxis - LDA.b OverworldMap16Buffer : SEC : SBC #$0400 : AND #$0F00 : ASL : XBA : STA.b OverworldTilemapIndexY ; vram - LDA.b OverworldMap16Buffer : SEC : SBC #$0010 : AND #$003E : LSR : STA.b OverworldTilemapIndexX + LDA.b OverworldMap16Buffer : SEC : SBC.w #$0400 : AND.w #$0F00 : ASL : XBA : STA.b OverworldTilemapIndexY ; vram + LDA.b OverworldMap16Buffer : SEC : SBC.w #$0010 : AND.w #$003E : LSR : STA.b OverworldTilemapIndexX .noLayoutShuffle LDA.w $000F,X : AND.w #$00FF : STA.w RandoOverworldWalkDist ; position to walk to after transition (if non-zero) @@ -920,47 +936,47 @@ OWNewDestination: pla : pla : sep #$10 : ldy.w TransitionDirection ldx.w OWCoordIndex,y : lda.b LinkPosY,x : and.w #$fe00 : pha lda.b LinkPosY,x : and.w #$01ff : pha ;s1 = relative cur, s3 = ow cur - lda.b Scrap06 : and #$fe00 : !sub.b 3,s : pha ;set coord, s1 = ow diff, s3 = relative cur, s5 = ow cur - lda.b Scrap06 : and.w #$01ff : !sub.b 3,s : pha ;s1 = rel diff, s3 = ow diff, s5 = relative cur, s7 = ow cur + lda.b Scrap06 : and.w #$fe00 : !SUB.b 3,s : pha ;set coord, s1 = ow diff, s3 = relative cur, s5 = ow cur + lda.b Scrap06 : and.w #$01ff : !SUB.b 3,s : pha ;s1 = rel diff, s3 = ow diff, s5 = relative cur, s7 = ow cur lda.b Scrap06 : sta.b LinkPosY,x : and.w #$fe00 : sta.b Scrap06 ;set coord - ldx.w OWBGIndex,y : lda.b BG2H,x : !add.b 1,s : adc.b 3,s : sta.b BG2H,x - ldx.w OWCameraIndex,y : lda.w CameraScrollN,x : !add.b 1,s : adc.b 3,s : sta.w CameraScrollN,x - ldx.w OWCameraIndex,y : lda.w CameraScrollS,x : !add.b 1,s : adc.b 3,s : sta.w CameraScrollS,x + ldx.w OWBGIndex,y : lda.b BG2H,x : !ADD.b 1,s : adc.b 3,s : sta.b BG2H,x + ldx.w OWCameraIndex,y : lda.w CameraScrollN,x : !ADD.b 1,s : adc.b 3,s : sta.w CameraScrollN,x + ldx.w OWCameraIndex,y : lda.w CameraScrollS,x : !ADD.b 1,s : adc.b 3,s : sta.w CameraScrollS,x pla : jsl DivideByTwoPreserveSign : pha - ldx.w OWBGIndex,y : lda.b BG1H,x : !add.b 1,s : sta.b BG1H,x : pla - ldx.w OWBGIndex,y : lda.b BG1H,x : !add.b 1,s : sta.b BG1H,x : pla + ldx.w OWBGIndex,y : lda.b BG1H,x : !ADD.b 1,s : sta.b BG1H,x : pla + ldx.w OWBGIndex,y : lda.b BG1H,x : !ADD.b 1,s : sta.b BG1H,x : pla pla : pla ;fix camera unlock - lda.b BG2H,x : !sub.b Scrap06 : bpl + + lda.b BG2H,x : !SUB.b Scrap06 : bpl + pha : lda.b Scrap06 : sta.b BG2H,x - ldx.w OWCameraIndex,y : lda.w CameraScrollN,x : !sub.b 1,s : sta.w CameraScrollN,x - lda.w CameraScrollS,x : !sub.b 1,s : sta.w CameraScrollS,x : pla + ldx.w OWCameraIndex,y : lda.w CameraScrollN,x : !SUB.b 1,s : sta.w CameraScrollN,x + lda.w CameraScrollS,x : !SUB.b 1,s : sta.w CameraScrollS,x : pla bra .adjustOppositeAxis - + lda.b Scrap06 : ldx.w OWCameraRangeIndex,y : !add.w OWCameraRange,x : sta.b Scrap06 - ldx.w OWBGIndex,y : !sub.b BG2H,x : bcs .adjustOppositeAxis + + lda.b Scrap06 : ldx.w OWCameraRangeIndex,y : !ADD.w OWCameraRange,x : sta.b Scrap06 + ldx.w OWBGIndex,y : !SUB.b BG2H,x : bcs .adjustOppositeAxis pha : lda.b Scrap06 : sta.b BG2H,x - ldx.w OWCameraIndex,y : lda.w CameraScrollN,x : !add.b 1,s : sta.w CameraScrollN,x - lda.w CameraScrollS,x : !add.b 1,s : sta.w CameraScrollS,x : pla + ldx.w OWCameraIndex,y : lda.w CameraScrollN,x : !ADD.b 1,s : sta.w CameraScrollN,x + lda.w CameraScrollS,x : !ADD.b 1,s : sta.w CameraScrollS,x : pla .adjustOppositeAxis ;opposite coord stuff - rep #$30 : lda OWOppDirectionOffset,y : and.w #$00ff : bit.w #$0080 : beq + + rep #$30 : lda.w OWOppDirectionOffset,y : and.w #$00ff : bit.w #$0080 : beq + ora.w #$ff00 ;extend 8-bit negative to 16-bit negative - + pha : cpy.w #$0002 : lda.w OverworldSlotPosition : !bge + - and.w #$00f0 : pha : lda.b Scrap04 : asl : and.w #$0070 : !sub.b 1,s : tax : pla : txa - !add 1,s : tax : pla : txa : asl : asl : asl : asl : asl : pha : bra ++ - + and.w #$000f : pha : lda.b Scrap04 : asl : and.w #$000f : !sub.b 1,s : !add.b 3,s + + pha : cpy.w #$0002 : lda.w OverworldSlotPosition : !BGE + + and.w #$00f0 : pha : lda.b Scrap04 : asl : and.w #$0070 : !SUB.b 1,s : tax : pla : txa + !ADD.b 1,s : tax : pla : txa : asl : asl : asl : asl : asl : pha : bra ++ + + and.w #$000f : pha : lda.b Scrap04 : asl : and.w #$000f : !SUB.b 1,s : !ADD.b 3,s sep #$10 : tax : phx : ldx.b #$0 : phx : rep #$10 : pla : plx : plx : pha - ++ sep #$10 : ldx OWOppCoordIndex,y : lda.b LinkPosY,x : !add.b 1,s : sta.b LinkPosY,x ;set coord - ldx OWOppBGIndex,y : lda.b BG2H,x : !add.b 1,s : sta.b BG2H,x - ldx OWOppCameraIndex,y : lda.w CameraScrollN,x : !add.b 1,s : sta.w CameraScrollN,x - ldx OWOppCameraIndex,y : lda.w CameraScrollS,x : !add.b 1,s : sta.w CameraScrollS,x - ldx OWOppBGIndex,y : lda.b BG1H,x : !add.b 1,s : sta.b BG1H,x - lda.w TransitionDirection : asl : tax : lda.w CameraTargetN,x : !add.b 1,s : sta.w CameraTargetN,x : pla + ++ sep #$10 : ldx.w OWOppCoordIndex,y : lda.b LinkPosY,x : !ADD.b 1,s : sta.b LinkPosY,x ;set coord + ldx.w OWOppBGIndex,y : lda.b BG2H,x : !ADD.b 1,s : sta.b BG2H,x + ldx.w OWOppCameraIndex,y : lda.w CameraScrollN,x : !ADD.b 1,s : sta.w CameraScrollN,x + ldx.w OWOppCameraIndex,y : lda.w CameraScrollS,x : !ADD.b 1,s : sta.w CameraScrollS,x + ldx.w OWOppBGIndex,y : lda.b BG1H,x : !ADD.b 1,s : sta.b BG1H,x + lda.w TransitionDirection : asl : tax : lda.w CameraTargetN,x : !ADD.b 1,s : sta.w CameraTargetN,x : pla - sep #$30 : lda.b Scrap04 : and.b #$3f : !add OWOppSlotOffset,y : asl : sta.w OverworldSlotPosition + sep #$30 : lda.b Scrap04 : and.b #$3f : !ADD.w OWOppSlotOffset,y : asl : sta.w OverworldSlotPosition ; crossed OW shuffle and terrain ldx.b Scrap05 : ldy.b Scrap08 : jsr OWWorldTerrainUpdate @@ -1186,6 +1202,12 @@ OWEndScrollTransition: CMP.l Overworld_FinalizeEntryOntoScreen_Data,X ; what we wrote over RTL } +OWSpecialReturnTriggerClear: +{ + STZ.b SubSubModule : STZ.b RoomIndex ; what we wrote over + STZ.w RandoOverworldTargetEdge + RTL +} ;Data org $aaa000 diff --git a/data/base2current.bps b/data/base2current.bps index 65e2169a..2c9e6421 100644 Binary files a/data/base2current.bps and b/data/base2current.bps differ diff --git a/source/enemizer/enemy_deny.yaml b/source/enemizer/enemy_deny.yaml index b3d94127..d6dc6564 100644 --- a/source/enemizer/enemy_deny.yaml +++ b/source/enemizer/enemy_deny.yaml @@ -77,7 +77,7 @@ UwGeneralDeny: - [ 0x0038, 4, [ "RollerHorizontalRight" ] ] #"Swamp Palace - Long Hall - Kyameron 2" - [ 0x0039, 3, [ "RollerVerticalUp", "RollerHorizontalLeft" ] ] #"Skull Woods - Play Pen - Mini Helmasaur" - [ 0x0039, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "FirebarCW", "FirebarCCW" ] ] #"Skull Woods - Play Pen - Spike Trap 1" - - [ 0x0039, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft" ] ] #"Skull Woods - Play Pen - Hardhat Beetle" + - [0x0039, 5, ["RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "Bumper"]] #"Skull Woods - Play Pen - Hardhat Beetle" - [ 0x0039, 6, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "FirebarCW", "FirebarCCW" ] ] #"Skull Woods - Play Pen - Spike Trap 2" - [ 0x003b, 1, [ "Bumper" ]] - [ 0x003c, 0, ["BigSpike"]] @@ -289,6 +289,8 @@ UwGeneralDeny: - [ 0x00ae, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ice Palace - Ice T - Blue Bari 1" - [ 0x00ae, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ice Palace - Ice T - Blue Bari 2" - [ 0x00af, 0, [ "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Ice Clock - Fire Bar (Clockwise)" + - [0x00b0, 7, [ "StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay + - [0x00b0, 8, [ "StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay - [ 0x00b1, 2, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Misery Mire - Hourglass - Spike Trap 1" - [ 0x00b1, 3, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Misery Mire - Hourglass - Spike Trap 2" - [ 0x00b1, 4, ["Bumper", "BigSpike", "AntiFairyCircle" ]] @@ -445,6 +447,7 @@ OwGeneralDeny: - [0x5e, 19, ["Gibo"]] # kiki eating Gibo - [0x5e, 20, ["Gibo"]] # kiki eating Gibo - [0x77, 1, ["Bumper"]] # soft-lock potential near ladder + - [0x7f, 1, ["Bumper"]] # soft-lock potential near ladder UwEnemyDrop: - [0x0085, 9, ["Babasu"]] # ran off the edge and didn't return - [0x00cb, 3, ["Zoro"]] # layer issues @@ -457,8 +460,6 @@ UwEnemyDrop: - [0x0077, 5, ["StalfosKnight", "Geldman", "Blob", "Stal", "Wizzrobe"]] - [0x008D, 10, ["StalfosKnight", "Geldman", "Blob", "Stal"]] - [0x008D, 12, ["StalfosKnight", "Geldman", "Blob", "Stal"]] - - [0x00b0, 7, ["StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay - - [0x00b0, 8, ["StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay # the following are not allowed at certain pits (or on conveyors near pits) # because they despawned or clipped away or immediately fell, etc - [0x003d, 9, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover", @@ -680,11 +681,11 @@ UwEnemyDrop: - [0x00a5, 4, ["GreenMimic", "RedMimic"]] - [0x00a5, 5, ["GreenMimic", "RedMimic"]] - [0x00a5, 6, ["GreenMimic", "RedMimic"]] - - [0x00bb, 1, ["GreenMimic", "RedMimic"]] - - [0x00bb, 4, ["GreenMimic", "RedMimic"]] - - [0x00bb, 5, ["GreenMimic", "RedMimic"]] - - [0x00bb, 6, ["GreenMimic", "RedMimic"]] - - [0x00bb, 7, ["GreenMimic", "RedMimic"]] + - [0x00bb, 1, ["GreenMimic", "RedMimic", "Terrorpin"]] + - [0x00bb, 4, ["GreenMimic", "RedMimic", "Terrorpin"]] + - [0x00bb, 5, ["GreenMimic", "RedMimic", "Terrorpin"]] + - [0x00bb, 6, ["GreenMimic", "RedMimic", "Terrorpin"]] + - [0x00bb, 7, ["GreenMimic", "RedMimic", "Terrorpin"]] - [0x00bb, 8, ["GreenMimic", "RedMimic"]] - [0x00bb, 9, ["GreenMimic", "RedMimic"]] - [0x00bb, 10, ["GreenMimic", "RedMimic"]]