diff --git a/BaseClasses.py b/BaseClasses.py index 40b48ec9..39a032fb 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -26,9 +26,10 @@ class World(object): self.teams = 1 self.owShuffle = owShuffle.copy() self.owTerrain = {} - self.owCrossed = owCrossed.copy() self.owKeepSimilar = {} self.owMixed = owMixed.copy() + self.owCrossed = owCrossed.copy() + self.owCrossed = self.owCrossed if self.owCrossed != 'polar' or self.owMixed else 'none' self.owWhirlpoolShuffle = {} self.owFluteShuffle = {} self.shuffle = shuffle.copy() diff --git a/CHANGELOG.md b/CHANGELOG.md index 3329232e..42ae2fb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.3.0.4 +- \~Merged in DR v1.2.0.14~ + - Fixed issue with enemy drops on OW enemies + - Fixed issue with magically opened doors +- Inverted + Vanilla ER can now generate +- Fixed issue with Multiworld bonk items not sending to correct player +- Minor improvements to OW Palettes on screen transition + ## 0.3.0.3 - Fixed issue with new Cold Fairy Statue location not dropping correct item - Fixed issue with Multiworld due to new Cold Fairy Statue location diff --git a/DoorShuffle.py b/DoorShuffle.py index 8e65a4cc..3ec1b985 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -323,6 +323,11 @@ def connect_simple_door(world, exit_name, region_name, player): d.dest = region +def connect_simple_door_to_region(exit_door, region): + exit_door.entrance.connect(region) + exit_door.dest = region + + def connect_door_only(world, exit_name, region, player): d = world.check_for_door(exit_name, player) if d is not None: @@ -355,6 +360,12 @@ def connect_two_way(world, entrancename, exitname, player): x.dest = y if y is not None: y.dest = x + if x.dependents: + for dep in x.dependents: + connect_simple_door_to_region(dep, ext.parent_region) + if y.dependents: + for dep in y.dependents: + connect_simple_door_to_region(dep, entrance.parent_region) def connect_one_way(world, entrancename, exitname, player): @@ -374,6 +385,9 @@ def connect_one_way(world, entrancename, exitname, player): y = world.check_for_door(exitname, player) if x is not None: x.dest = y + if x.dependents: + for dep in x.dependents: + connect_simple_door_to_region(dep, ext.parent_region) def unmark_ugly_smalls(world, player): for d in ['Eastern Hint Tile Blocked Path SE', 'Eastern Darkness S', 'Thieves Hallway SE', 'Mire Left Bridge S', @@ -1814,7 +1828,8 @@ def shuffle_door_types(door_type_pools, paths, world, player): for dungeon, doors in custom_dict.items(): all_custom[dungeon].extend(doors) - world.paired_doors[player].clear() + for pd in world.paired_doors[player]: + pd.pair = False used_doors = shuffle_trap_doors(door_type_pools, paths, start_regions_map, all_custom, world, player) # big keys used_doors = shuffle_big_key_doors(door_type_pools, used_doors, start_regions_map, all_custom, world, player) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index dc6e6fd4..bc754b89 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2740,7 +2740,7 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Lost Woods Gamble': (0x240, 0x080), 'Fortune Teller (Light)': (0x2c0, 0x4c0), 'Snitch Lady (East)': (0x310, 0x7a0), - 'Snitch Lady (West)': (0x800, 0x7a0), + 'Snitch Lady (West)': (0x080, 0x7a0), 'Bush Covered House': (0x2e0, 0x880), 'Tavern (Front)': (0x270, 0x980), 'Light World Bomb Hut': (0x070, 0x980), diff --git a/Fill.py b/Fill.py index d549e969..0c1033b2 100644 --- a/Fill.py +++ b/Fill.py @@ -670,9 +670,10 @@ def sell_potions(world, player): for potion in ['Green Potion', 'Blue Potion', 'Red Potion']: location = random.choice(filter_locations(ItemFactory(potion, player), locations, world, potion=True)) locations.remove(location) - p_item = next(item for item in world.itempool if item.name == potion and item.player == player) - world.push_item(location, p_item, collect=False) - world.itempool.remove(p_item) + p_item = next((item for item in world.itempool if item.name == potion and item.player == player), None) + if p_item: + world.push_item(location, p_item, collect=False) + world.itempool.remove(p_item) def sell_keys(world, player): diff --git a/KeyDoorShuffle.py b/KeyDoorShuffle.py index 3549f39f..54ebbf23 100644 --- a/KeyDoorShuffle.py +++ b/KeyDoorShuffle.py @@ -1561,13 +1561,18 @@ def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposa def invalid_self_locking_key(key_layout, state, prev_state, prev_avail, world, player): if prev_state is None or state.used_smalls == prev_state.used_smalls: return False - new_bk_doors = set(state.big_doors).difference(set(prev_state.big_doors)) - state_copy = state.copy() - while len(new_bk_doors) > 0: - for door in new_bk_doors: - open_a_door(door.door, state_copy, key_layout.flat_prop, world, player) - new_bk_doors = set(state_copy.big_doors).difference(set(prev_state.big_doors)) - expand_key_state(state_copy, key_layout.flat_prop, world, player) + if state.found_forced_bk() and not prev_state.found_forced_bk(): + return False + if state.big_key_opened: + new_bk_doors = set(state.big_doors).difference(set(prev_state.big_doors)) + state_copy = state.copy() + while len(new_bk_doors) > 0: + for door in new_bk_doors: + open_a_door(door.door, state_copy, key_layout.flat_prop, world, player) + new_bk_doors = set(state_copy.big_doors).difference(set(prev_state.big_doors)) + expand_key_state(state_copy, key_layout.flat_prop, world, player) + else: + state_copy = state new_locations = set(state_copy.found_locations).difference(set(prev_state.found_locations)) important_found = False for loc in new_locations: diff --git a/Main.py b/Main.py index 08cd7ff0..5b1a2384 100644 --- a/Main.py +++ b/Main.py @@ -36,7 +36,9 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -__version__ = '1.2.0.12u' +version_number = '1.2.0.14' +version_branch = '-u' +__version__ = f'{version_number}{version_branch}' from source.classes.BabelFish import BabelFish @@ -265,6 +267,7 @@ def main(args, seed=None, fish=None): set_rules(world, player) district_item_pool_config(world) + fill_specific_items(world) for player in range(1, world.players + 1): if world.shopsanity[player]: sell_potions(world, player) @@ -277,8 +280,6 @@ def main(args, seed=None, fish=None): if args.print_custom_yaml: world.settings.record_item_pool(world) dungeon_tracking(world) - fill_specific_items(world) - logger.info(world.fish.translate("cli", "cli", "placing.dungeon.prizes")) fill_prizes(world) diff --git a/MultiServer.py b/MultiServer.py index 4108b8dd..a9f9e9e2 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -46,6 +46,9 @@ class Context: self.lookup_name_to_id = {} self.lookup_id_to_name = {} + self.disable_client_forfeit = False + + async def send_msgs(websocket, msgs): if not websocket or not websocket.open or websocket.closed: return @@ -281,7 +284,10 @@ async def process_client_cmd(ctx : Context, client : Client, cmd, args): if args.startswith('!players'): notify_all(ctx, get_connected_players_string(ctx)) if args.startswith('!forfeit'): - forfeit_player(ctx, client.team, client.slot) + if ctx.disable_client_forfeit: + notify_client(client, 'Client-initiated forfeits are disabled. Please ask the host of this game to forfeit on your behalf.') + else: + forfeit_player(ctx, client.team, client.slot) if args.startswith('!countdown'): try: timer = int(args.split()[1]) diff --git a/OWEdges.py b/OWEdges.py index 1e40a0c4..cf397f18 100644 --- a/OWEdges.py +++ b/OWEdges.py @@ -143,7 +143,7 @@ def create_owedges(world, player): create_owedge(player, 'Tree Line WC', 0x2e, We, Wr, 0x1a) .coordInfo(0x0b3c, 0x0660), create_owedge(player, 'Eastern Nook NE', 0x2f, No, Ld, 0x16) .coordInfo(0x0f78, 0x1820), create_owedge(player, 'Desert EC', 0x30, Ea, Ld, 0x1e, 0x39).coordInfo(0x0ee4, 0x1480), - create_owedge(player, 'Desert ES', 0x30, Ea, Ld, 0x1f, 0x39).coordInfo(0x0f8c, 0x1980), + create_owedge(player, 'Desert ES', 0x30, Ea, Ld, 0x1f, 0x39).coordInfo(0x0f90, 0x1980), create_owedge(player, 'Flute Boy Approach NW', 0x32, No, Ld, 0x17) .coordInfo(0x044c, 0x1800), create_owedge(player, 'Flute Boy Approach NC', 0x32, No, Ld, 0x18) .coordInfo(0x04e8, 0x180c), create_owedge(player, 'Flute Boy Approach EC', 0x32, Ea, Ld, 0x1a) .coordInfo(0x0d04, 0x05c0), @@ -167,7 +167,7 @@ def create_owedges(world, player): create_owedge(player, 'Ice Cave SW', 0x37, So, Wr, 0x1e) .coordInfo(0x0e80, 0x1002), create_owedge(player, 'Ice Cave SE', 0x37, So, Ld, 0x1f) .coordInfo(0x0f50, 0x101c), create_owedge(player, 'Desert Pass WC', 0x3a, We, Ld, 0x1f) .coordInfo(0x0ee4, 0x03e0), - create_owedge(player, 'Desert Pass WS', 0x3a, We, Ld, 0x20) .coordInfo(0x0f8c, 0x0860), + create_owedge(player, 'Desert Pass WS', 0x3a, We, Ld, 0x20) .coordInfo(0x0f90, 0x0860), create_owedge(player, 'Desert Pass EC', 0x3a, Ea, Ld, 0x20) .coordInfo(0x0f18, 0x0640), create_owedge(player, 'Desert Pass ES', 0x3a, Ea, Ld, 0x21) .coordInfo(0x0fcb, 0x08c0), create_owedge(player, 'Dam NC', 0x3b, No, Ld, 0x1e) .coordInfo(0x0728, 0x1816), diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 8dc428b9..b5e69c25 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.0.3' +version_number = '0.3.0.4' # branch indicator is intentionally different across branches version_branch = '' diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 317db6b2..71d39a67 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -108,6 +108,17 @@ These are now independent of retro mode and have three options: None, Random, an * Bonk Fairy (Dark) # Bug Fixes and Notes + +* 1.2.0.14u + * Small fix for key logic validation (got rid of a false negative) + * Customized doors in ice cross work properly now +* 1.2.0.13u + * Allow green/blue potion refills to be customized + * OW Map showing dungeon entrance at Snitch Lady (West) fixed (instead of @ HC Courtyard) + * Standing item data is cleared on transition to overworld (enemy drops won't bleed to overworld sprites) + * Escape assist won't give you a free quiver in retro bow mode + * Fixed an issue where a door would be opened magically (due to original pairing) + * MultiServer can now disable forfeits if desired * 1.2.0.12u * Fix for mirror portal in inverted * Yet another fix for blocked door in Standard ER diff --git a/Rom.py b/Rom.py index f351d017..cc784646 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'c27bdd316ea8312214643e0a4ea32c10' +RANDOMIZERBASEHASH = '0a3d1d4bbec659013be5ed876c2658bd' class JsonRom(object): @@ -1710,12 +1710,16 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): # set rom name # 21 bytes from Main import __version__ + from OverworldShuffle import __version__ as ORVersion seedstring = f'{world.seed:09}' if isinstance(world.seed, int) else world.seed # todo: change to DR when Enemizer is okay with DR rom.name = bytearray(f'ER{__version__.split("-")[0].replace(".","")[0:3]}_{team+1}_{player}_{seedstring}O\0', 'utf8')[:21] rom.name.extend([0] * (21 - len(rom.name))) rom.write_bytes(0x7FC0, rom.name) + rom.write_bytes(0x138010, bytearray(__version__, 'utf8')) + rom.write_bytes(0x150010, bytearray(ORVersion, 'utf8')) + # set player names for p in range(1, min(world.players, 255) + 1): rom.write_bytes(0x195FFC + ((p - 1) * 32), hud_format_text(world.player_names[p][team])) diff --git a/Text.py b/Text.py index 5d023818..bf4f22cb 100644 --- a/Text.py +++ b/Text.py @@ -113,7 +113,7 @@ Triforce_texts = [ " Cool seed,\n\n right?", "\n We did it!", " Spam those\n emotes in\n wilds chat", - "\n O M G", + "\n O M G", " Hello. Will you\n you be my friend?", " Beetorp\n was\n here!", " The Wind Fish\n will wake soon.\n Hoot!", @@ -1309,6 +1309,7 @@ class GoldCreditMapper(CharTextMapper): class GreenCreditMapper(CharTextMapper): char_map = {' ': 0x9F, + '.': 0x52, 'ยท': 0x52} alpha_offset = -0x29 alpha_lower_offset = -0x29 diff --git a/asm/owrando.asm b/asm/owrando.asm index c65ca10c..a308a9fc 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -11,9 +11,11 @@ OWMode: dw 0 OWFlags: dw 0 -org $aa8010 OWReserved: dw 0 +org $aa8010 +OWVersionInfo: +dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ;Hooks org $02a929 @@ -45,6 +47,10 @@ Overworld_LoadSpecialOverworld_RoomId: org $04E8B4 Overworld_LoadSpecialOverworld: +org $02A9DA +JSL OWSkipPalettes +BCC OverworldHandleTransitions_change_palettes : NOP #4 + org $07982A Link_ResetSwimmingState: @@ -238,6 +244,19 @@ OWWhirlpoolEnd: RTL } +OWDestroyItemSprites: +{ + PHX : LDX.b #$0F + .nextSprite + LDA.w $0E20,X + CMP.b #$D8 : BCC .continue + CMP.b #$EC : BCS .continue + .killSprite ; need to kill sprites from D8 to EB on screen transition + STZ.w $0DD0,X + .continue + DEX : BPL .nextSprite + PLX : RTL +} OWMirrorSpriteOnMap: { lda.w $1ac0,x : bit.b #$f0 : beq .continue @@ -421,7 +440,7 @@ OWBonkGoodBeeDrop: JMP .spawn_item + - .determine_type ; S = Collected, FlagBitmask, X (row + 2) + .determine_type ; S = Collected LDA.l OWBonkPrizeTable[42].loot ; A = item id CMP.b #$B0 : BNE + LDA.b #$79 : JMP .sprite_transform ; transform to bees @@ -465,33 +484,34 @@ OWBonkGoodBeeDrop: JSL.l OWBonkSpritePrep .mark_collected ; S = Collected - PLA : BNE .return + PLA : BNE + LDA.l RoomDataWRAM[$0120].high : ORA.b #$02 : STA.l RoomDataWRAM[$0120].high REP #$20 LDA.l TotalItemCounter : INC : STA.l TotalItemCounter SEP #$20 - BRA .return + + BRA .return ; spawn itemget item .spawn_item ; A = item id ; Y = bonk sprite slot ; S = Collected PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : BRA .return - + LDA.l OWBonkPrizeTable[42].mw_player : STA.l !MULTIWORLD_SPRITEITEM_PLAYER_ID - - LDA.b #$01 : STA !REDRAW + + LDA.b #$01 : STA !REDRAW LDA.b #$EB : STA.l $7FFE00 JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite + TYX : STZ.w $0F20,X ; layer the sprite is on + ; affects the rate the item moves in the Y/X direction - LDA.b #$00 : STA.w $0D40,Y + STZ.w $0D40,X LDA.b #$0A : STA.w $0D50,Y - LDA.b #$20 : STA.w $0F80,Y ; amount of force (gives height to the arch) + LDA.b #$1A : STA.w $0F80,Y ; amount of force (gives height to the arch) LDA.b #$FF : STA.w $0B58,Y ; stun timer LDA.b #$30 : STA.w $0F10,Y ; aux delay timer 4 ?? dunno what that means - LDA.b #$00 : STA.w $0F20,Y ; layer the sprite is on + ; sets the tile type that is underneath the sprite, water + LDA.b #$09 : STA.l $7FF9C2,X ; TODO: Figure out how to get the game to set this ; sets OW event bitmask flag, uses free RAM LDA.l OWBonkPrizeTable[42].flag : STA.w $0ED0,Y @@ -597,9 +617,7 @@ OWBonkDrops: ; spawn itemget item .spawn_item ; A = item id ; Y = tree sprite slot ; S = Collected, FlagBitmask, X (row + 2) PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : JMP .return ; S = FlagBitmask, X (row + 2) - + LDA 2,S : TAX : INX : INX - LDA.w OWBonkPrizeData,X : STA.l !MULTIWORLD_SPRITEITEM_PLAYER_ID - DEX + + LDA 2,S : TAX : INX LDA.b #$01 : STA !REDRAW @@ -610,7 +628,7 @@ OWBonkDrops: LDA.b #$00 : STA.w $0D40,Y LDA.b #$0A : STA.w $0D50,Y - LDA.b #$20 : STA.w $0F80,Y ; amount of force (gives height to the arch) + LDA.b #$1A : STA.w $0F80,Y ; amount of force (gives height to the arch) LDA.b #$FF : STA.w $0B58,Y ; stun timer LDA.b #$30 : STA.w $0F10,Y ; aux delay timer 4 ?? dunno what that means @@ -648,6 +666,7 @@ OWBonkSpritePrep: org $aa9000 OWDetectEdgeTransition: { + JSL OWDestroyItemSprites STZ.w $06FC LDA.l OWMode : ORA.l OWMode+1 : BEQ .vanilla JSR OWShuffle @@ -925,8 +944,12 @@ OWNewDestination: ; crossed OW shuffle and terrain ldx $05 : ldy $08 : jsr OWWorldTerrainUpdate + + ldx $8a : lda $05 : sta $8a : stx $05 ; $05 is prev screen id, $8a is dest screen - lda $05 : sta $8a + jsr OWGfxUpdate + + lda $8a rep #$30 : rts } OWLoadSpecialArea: @@ -966,17 +989,17 @@ OWWorldTerrainUpdate: ; x = owid of destination screen, y = 1 for land to water, lda #$38 : sta $012f ; play sfx - #$3b is an alternative ; toggle bunny mode - lda MoonPearlEquipment : bne .nobunny - lda.l InvertedMode : bne .inverted + lda MoonPearlEquipment : beq + : jmp .nobunny + + lda.l InvertedMode : bne .inverted lda CurrentWorld : bra + .inverted lda CurrentWorld : eor #$40 + and #$40 : beq .nobunny - LDA.w $0703 : BEQ + ; check if forced transition - CPY.b #$03 : BEQ .end_forced_whirlpool - LDA.b #$17 : STA.b $5D - LDA.b #$01 : STA.w $02E0 : STA.b $56 - LDA.w $0703 : BRA .end_forced_edge + CPY.b #$03 : BEQ ++ + LDA.b #$17 : STA.b $5D + LDA.b #$01 : STA.w $02E0 : STA.b $56 + LDA.w $0703 : JSR OWLoadGearPalettes : BRA .end_forced_edge + ++ JSR OWLoadGearPalettes : BRA .end_forced_whirlpool + CPY.b #$01 : BEQ .auto ; check if going from land to water CPY.b #$02 : BEQ .to_bunny_reset_swim ; bunny state if swimming to land @@ -995,8 +1018,8 @@ OWWorldTerrainUpdate: ; x = owid of destination screen, y = 1 for land to water, STZ.b $5D PLX BRA .to_pseudo_bunny - .whirlpool - PLX : RTS + .whirlpool + PLX : JMP OWLoadGearPalettes .to_bunny_reset_swim LDA.b $5D : CMP.b #$04 : BNE .to_bunny ; check if swimming JSL Link_ResetSwimmingState @@ -1005,7 +1028,7 @@ OWWorldTerrainUpdate: ; x = owid of destination screen, y = 1 for land to water, LDA.b #$17 : STA.b $5D .to_pseudo_bunny LDA.b #$01 : STA.w $02E0 : STA.b $56 - RTS + JMP OWLoadGearPalettes .nobunny lda $5d : cmp #$17 : bne + ; retain current state unless bunny @@ -1054,6 +1077,68 @@ OWWorldTerrainUpdate: ; x = owid of destination screen, y = 1 for land to water, .return RTS } +OWGfxUpdate: +{ + REP #$20 : LDA.l OWMode : AND.w #$0207 : BEQ .is_only_mixed : SEP #$20 + ;;;;PLA : AND.b #$3F : BEQ .leaving_woods + LDA.b $8A : AND.b #$3F : BEQ .entering_woods + ;LDA.b $05 : JSL OWSkipPalettes : BCS .skip_palettes + LDA.b $8A : JSR OWDetermineScreensPaletteSet + CPX.w $0AB3 : BEQ .skip_palettes ; check if next screen's palette is different + LDA $00 : PHA + JSL OverworldLoadScreensPaletteSet_long ; loading correct OW palette + PLA : STA $00 + .leaving_woods + .entering_woods + .is_only_mixed + .skip_palettes + SEP #$20 +} +OWLoadGearPalettes: +{ + PHX : PHY : LDA $00 : PHA + LDA.w $02E0 : BEQ + + JSL LoadGearPalettes_bunny + BRA .return + + + JSL LoadGearPalettes_link + .return + PLA : STA $00 : PLY : PLX + RTS +} +OWDetermineScreensPaletteSet: ; A = OWID to check +{ + LDX.b #$02 + PHA : AND.b #$3F + CMP.b #$03 : BEQ .death_mountain + CMP.b #$05 : BEQ .death_mountain + CMP.b #$07 : BEQ .death_mountain + LDX.b #$00 + .death_mountain + PLA : PHX : TAX : LDA.l OWTileWorldAssoc,X : BEQ + + PLX : INX : RTS + + PLX : RTS +} +OWSkipPalettes: +{ + STA.b $05 ; A = previous screen, also stored in $05 + ; only skip mosaic if OWR Layout or Crossed + PHP : REP #$20 : LDA.l OWMode : AND.w #$0207 : BEQ .vanilla : PLP + ; checks to see if going to from any DM screens + ;LDA.b $05 : JSR OWDetermineScreensPaletteSet : TXA : AND.b #$FE : STA $04 + ;LDA.b $8A : JSR OWDetermineScreensPaletteSet : TXA : AND.b #$FE + ;CMP.b $04 : BNE .skip_palettes + BRA .vanilla+1 + + .vanilla + PLP + LDA.b $05 : AND.b #$3F : BEQ .skip_palettes ; what we + LDA.b $8A : AND.b #$BF : BNE .change_palettes ; wrote over, kinda + .skip_palettes + SEC : RTL ; mosaic transition occurs + .change_palettes + CLC : RTL +} OWAdjustExitPosition: { LDA.w $06FC : CMP.b #$60 : BEQ .stone_bridge @@ -1407,7 +1492,7 @@ dw $0c78, $0ce3, $006b, $0cad, $3434, $0000, $0000, $001b dw $0ce4, $0d33, $004f, $0d0b, $3434, $0000, $0001, $001c dw $0d34, $0db8, $0084, $0d76, $3434, $0000, $0000, $001d dw $0ea8, $0f20, $0078, $0ee4, $3a3a, $0000, $0000, $001e -dw $0f70, $0fa8, $0038, $0f8c, $3a3a, $0000, $0000, $001f +dw $0f78, $0fa8, $0030, $0f90, $3a3a, $0000, $0000, $001f dw $0f18, $0f18, $0000, $0f18, $3b3b, $0000, $0000, $0020 dw $0fc8, $0fc8, $0000, $0fc8, $3b3b, $0000, $0000, $0021 dw $0e28, $0fb8, $0190, $0ef0, $3c3c, $0000, $0000, $0022 @@ -1482,7 +1567,7 @@ dw $0c78, $0ce3, $006b, $0cad, $3333, $0000, $0000, $001c dw $0ce4, $0d33, $004f, $0d0b, $3333, $0000, $0001, $001d dw $0d34, $0db8, $0084, $0d76, $3333, $0000, $0000, $001e dw $0ea8, $0f20, $0078, $0ee4, $3039, $0000, $0000, $001f -dw $0f70, $0fa8, $0038, $0f8c, $3039, $0000, $0000, $0020 +dw $0f78, $0fa8, $0030, $0f90, $3039, $0000, $0000, $0020 dw $0f18, $0f18, $0000, $0f18, $3a3a, $0000, $0000, $0021 dw $0fc8, $0fc8, $0000, $0fc8, $3a3a, $0000, $0000, $0022 dw $0e28, $0fb8, $0190, $0ef0, $3b3b, $0000, $0000, $0023 diff --git a/data/base2current.bps b/data/base2current.bps index afa8a164..d492f90b 100644 Binary files a/data/base2current.bps and b/data/base2current.bps differ diff --git a/docs/standardinverted.yaml b/docs/standardinverted.yaml index c5590090..8195851a 100644 --- a/docs/standardinverted.yaml +++ b/docs/standardinverted.yaml @@ -4,7 +4,15 @@ settings: 1: mode: standard ow_mixed: true +entrances: + 1: + entrances: + Sanctuary Grave: Sewer Drop + two-way: + Sanctuary: Sanctuary Exit ow-tileflips: 1: + force_no_flip: + - 0x13 undefined_chance: 100 diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 3515fa47..c6898b3a 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -171,6 +171,9 @@ def do_vanilla_connections(avail_pool): connect_vanilla_two_way(ent, avail_pool.default_map[ent], avail_pool) if ent in avail_pool.one_way_map and avail_pool.one_way_map[ent] in avail_pool.exits: connect_vanilla(ent, avail_pool.one_way_map[ent], avail_pool) + if avail_pool.inverted: + ext = avail_pool.world.get_entrance('Dark Sanctuary Hint Exit', avail_pool.player) + ext.connect(avail_pool.world.get_region('Dark Chapel Area', avail_pool.player)) def do_main_shuffle(entrances, exits, avail, mode_def):