Merge branch 'OverworldShuffleDev' into OverworldShuffle

This commit is contained in:
codemann8
2024-05-30 23:26:27 -05:00
17 changed files with 153 additions and 22 deletions

View File

@@ -367,7 +367,7 @@ jobs:
with: with:
tag_name: ${{ steps.debug_info.outputs.github_tag }} tag_name: ${{ steps.debug_info.outputs.github_tag }}
release_name: ${{ steps.debug_info.outputs.release_name }} release_name: ${{ steps.debug_info.outputs.release_name }}
body_path: RELEASENOTES.md body_path: CHANGELOG.md
# draft: true # draft: true
if: contains(github.ref, 'OverworldShuffle') && contains(github.event.head_commit.message, 'Version bump') # branch/tag name and commit message if: contains(github.ref, 'OverworldShuffle') && contains(github.event.head_commit.message, 'Version bump') # branch/tag name and commit message

2
.gitignore vendored
View File

@@ -42,6 +42,8 @@ get-pip.py
venv venv
/test /test
test_games/ test_games/
docs/issues/*
docs/ideas/*
data/sprites/official/selan.1.zspr data/sprites/official/selan.1.zspr
*.zspr *.zspr

View File

@@ -1,5 +1,19 @@
# Changelog # Changelog
## 0.5.0.1
- Fixed HP refill interrupting boss cutscenes
- Fixed incorrect compass counts in Prize Shuffle
- Various QoL to Prize Shuffle for less confusion on map checks
- Color-blind support for red crystals (item receipt and map check)
- Added X icon on flute map to indicate you can cancel out of flute menu (Flute Shuffle only)
## 0.5.0.0
- Overworld Map Check has been overhauled
- Dungeon Prize Indicators have changed: P/C no longer display, replaced by G/B/R/1-7
- New Mode: Prize Shuffle
- Death Mountain Return Cave and Paradox Cave (Top) are no longer bunny passable
- \~Merged in DR v1.4.1.12~
## 0.4.0.2 ## 0.4.0.2
- Fixed issue with Inverted GT entrance not opening - Fixed issue with Inverted GT entrance not opening
- Potential fox for bonk items duplicating onto other OW items - Potential fox for bonk items duplicating onto other OW items

View File

@@ -205,7 +205,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche
} }
prize_item_table = { prize_item_table = {
'Green Pendant': [0x04, 0x38, 0x62, 0x00, 0x69, 0x08], 'Green Pendant': [0x04, 0x38, 0x60, 0x00, 0x69, 0x08],
'Blue Pendant': [0x02, 0x34, 0x60, 0x00, 0x69, 0x09], 'Blue Pendant': [0x02, 0x34, 0x60, 0x00, 0x69, 0x09],
'Red Pendant': [0x01, 0x32, 0x60, 0x00, 0x69, 0x0a], 'Red Pendant': [0x01, 0x32, 0x60, 0x00, 0x69, 0x0a],
'Crystal 1': [0x02, 0x34, 0x64, 0x40, 0x7F, 0x01], 'Crystal 1': [0x02, 0x34, 0x64, 0x40, 0x7F, 0x01],

View File

@@ -386,7 +386,7 @@ def create_exhaustive_placement_rules(key_layout, world, player):
rule.bk_conditional_set = blocked_loc rule.bk_conditional_set = blocked_loc
rule.needed_keys_wo_bk = min_keys rule.needed_keys_wo_bk = min_keys
rule.check_locations_wo_bk = set(filter_big_chest(accessible_loc)) rule.check_locations_wo_bk = set(filter_big_chest(accessible_loc))
rule.prize_relevance = key_layout.prize_relevant if rule_prize_relevant(key_counter) else None rule.prize_relevance = key_layout.prize_relevant if world.prizeshuffle[player] == 'none' and rule_prize_relevant(key_counter) else None
if valid_rule: if valid_rule:
key_logic.placement_rules.append(rule) key_logic.placement_rules.append(rule)
adjust_locations_rules(key_logic, rule, accessible_loc, key_layout, key_counter, max_ctr) adjust_locations_rules(key_logic, rule, accessible_loc, key_layout, key_counter, max_ctr)
@@ -1438,7 +1438,7 @@ def validate_bk_layout(proposal, builder, start_regions, world, player):
for region in start_regions: for region in start_regions:
dungeon_entrance, portal_door = find_outside_connection(region) dungeon_entrance, portal_door = find_outside_connection(region)
prize_relevant_flag = prize_relevance_sig2(start_regions, builder.name, dungeon_entrance, world.is_atgt_swapped(player)) prize_relevant_flag = prize_relevance_sig2(start_regions, builder.name, dungeon_entrance, world.is_atgt_swapped(player))
if prize_relevant_flag: if prize_relevant_flag and world.prizeshuffle[player] == 'none':
state.append_door_to_list(portal_door, state.prize_doors) state.append_door_to_list(portal_door, state.prize_doors)
state.prize_door_set[portal_door] = dungeon_entrance state.prize_door_set[portal_door] = dungeon_entrance
# key_layout.prize_relevant = prize_relevant_flag # key_layout.prize_relevant = prize_relevant_flag
@@ -1469,7 +1469,7 @@ def validate_key_layout(key_layout, world, player):
for region in key_layout.start_regions: for region in key_layout.start_regions:
dungeon_entrance, portal_door = find_outside_connection(region) dungeon_entrance, portal_door = find_outside_connection(region)
prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player)) prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player))
if prize_relevant_flag: if prize_relevant_flag and world.prizeshuffle[player] == 'none':
state.append_door_to_list(portal_door, state.prize_doors) state.append_door_to_list(portal_door, state.prize_doors)
state.prize_door_set[portal_door] = dungeon_entrance state.prize_door_set[portal_door] = dungeon_entrance
key_layout.prize_relevant = prize_relevant_flag key_layout.prize_relevant = prize_relevant_flag
@@ -1606,7 +1606,7 @@ def determine_prize_lock(key_layout, world, player):
for region in key_layout.start_regions: for region in key_layout.start_regions:
dungeon_entrance, portal_door = find_outside_connection(region) dungeon_entrance, portal_door = find_outside_connection(region)
prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player)) prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player))
if prize_relevant_flag: if prize_relevant_flag and world.prizeshuffle[player] == 'none':
state.append_door_to_list(portal_door, state.prize_doors) state.append_door_to_list(portal_door, state.prize_doors)
state.prize_door_set[portal_door] = dungeon_entrance state.prize_door_set[portal_door] = dungeon_entrance
key_layout.prize_relevant = prize_relevant_flag key_layout.prize_relevant = prize_relevant_flag
@@ -1683,7 +1683,7 @@ def create_key_counters(key_layout, world, player):
for region in key_layout.start_regions: for region in key_layout.start_regions:
dungeon_entrance, portal_door = find_outside_connection(region) dungeon_entrance, portal_door = find_outside_connection(region)
prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player)) prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player))
if prize_relevant_flag: if prize_relevant_flag and world.prizeshuffle[player] == 'none':
state.append_door_to_list(portal_door, state.prize_doors) state.append_door_to_list(portal_door, state.prize_doors)
state.prize_door_set[portal_door] = dungeon_entrance state.prize_door_set[portal_door] = dungeon_entrance
key_layout.prize_relevant = prize_relevant_flag key_layout.prize_relevant = prize_relevant_flag

View File

@@ -8,7 +8,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType
from OverworldGlitchRules import create_owg_connections from OverworldGlitchRules import create_owg_connections
from Utils import bidict from Utils import bidict
version_number = '0.5.0.0' version_number = '0.5.0.1'
# branch indicator is intentionally different across branches # branch indicator is intentionally different across branches
version_branch = '' version_branch = ''

View File

@@ -107,7 +107,7 @@ Similar edges are used when `Keep Similar Edges Together` is enabled and have me
# Overworld Map Changes # Overworld Map Changes
The overworld map check screen has been completely overhauled in this OWR fork. In other LTTP forks, there are numbered icons to indicate the crystal number of the crystal and those are shown alongside crystal prizes. OWR has changed this so the numbers instead correspond to dungeon numbers. In the LW, you have the 3 pendant dungeons, these are indicated by a blue 1, 2, and 3. In the DW, you have the 7 crystal dungeon, these are indicated by red numbers (1-7). In addition, there may be some mode combinations where HC, AT, and GT may be visible via icon, indicated by a white H, a white A, and a skull. An example of what you can expect to see on a map check can be found [here](https://cdn.discordapp.com/attachments/783989090017738753/1243839950663847936/newmapcheck.gif?ex=6652efb9&is=66519e39&hm=8be1d514458c09d6881a0d6ae0e539adf1f6227374a7d61a8f3a1831e18f0395&). The overworld map check screen has been completely overhauled in this OWR fork. In other LTTP forks, there are numbered icons to indicate the crystal number of the crystal and those are shown alongside crystal prizes. OWR has changed this so the numbers instead correspond to dungeon numbers. In the LW, you have the 3 pendant dungeons, these are indicated by a blue 1, 2, and 3. In the DW, you have the 7 crystal dungeon, these are indicated by red numbers (1-7). In addition, there may be some mode combinations where HC, AT, and GT may be visible via icon, indicated by a white H, a white A, and a skull. An example of what you can expect to see on a map check can be found [here](https://zelda.codemann8.com/images/shared/newmapcheck.gif).
# Inverted Changes # Inverted Changes
@@ -133,7 +133,7 @@ Note: These changes do impact the logic. If you use `CodeTracker`, these Inverte
Only settings specifically added by this Overworld Shuffle fork are found here. All door and entrance randomizer settings are supported. See their [readme](https://github.com/Aerinon/ALttPDoorRandomizer/blob/master/README.md) Only settings specifically added by this Overworld Shuffle fork are found here. All door and entrance randomizer settings are supported. See their [readme](https://github.com/Aerinon/ALttPDoorRandomizer/blob/master/README.md)
## Overworld Layout Shuffle (--ow_shuffle) ## Overworld Layout Shuffle (--ow_shuffle)
OW Edge Transitions are shuffled to create new world layouts. A brief visual representation of this can be viewed [here](https://cdn.discordapp.com/attachments/783989090017738753/857299555183362078/ow-modes.gif?ex=66044c6d&is=65f1d76d&hm=b43ebd1b22e0a86c7caf3153c217ba14174bb92a2b168c15fe8e75364b5c8c15&). (This graphic also includes combinations of Crossed and Tile Flip) OW Edge Transitions are shuffled to create new world layouts. A brief visual representation of this can be viewed [here](https://zelda.codemann8.com/images/shared/ow-modes.gif). (This graphic also includes combinations of Crossed and Tile Flip)
### Vanilla ### Vanilla
@@ -193,7 +193,7 @@ Being that this uses concepts from Inverted, it will be important to review the
During gameplay: During gameplay:
- When on the OW, there will be an L or D in the upper left corner, indicating which world you are currently in. Mirroring still works the same, you must be in the DW to mirror to the LW. - When on the OW, there will be an L or D in the upper left corner, indicating which world you are currently in. Mirroring still works the same, you must be in the DW to mirror to the LW.
- When doing a map check (pressing X while on the OW), the tiles shown will reflect the flipped tiles. This means that dungeon prizes will show the prizes for the dungeons that are now part of that world. Here is an image showing the difference of appearance when tiles are flipped on the [map check](https://cdn.discordapp.com/attachments/783989090017738753/970646558049714196/lttp-lw-mapcheck.gif?ex=665272cd&is=6651214d&hm=6962fe0b16a7919a91066e96fea29d28fbecd404e6c0dc344146f17553425296&) screen. - When doing a map check (pressing X while on the OW), the tiles shown will reflect the flipped tiles. This means that dungeon prizes will show the prizes for the dungeons that are now part of that world. Here is an image showing the difference of appearance when tiles are flipped on the [map check](https://zelda.codemann8.com/images/shared/lttp-lw-mapcheck.gif) screen.
Note: Tiles are put into Tile Groups (see `Terminology`) that must be shuffled together when certain settings are enabled. For instance, if ER is disabled, then any tiles that have a connector cave that leads to a different tile, then those tiles must flip together. Note: Tiles are put into Tile Groups (see `Terminology`) that must be shuffled together when certain settings are enabled. For instance, if ER is disabled, then any tiles that have a connector cave that leads to a different tile, then those tiles must flip together.
@@ -252,7 +252,7 @@ This adds 42 new item locations to the game. These bonk locations are limited to
- Some screens are coded to change the "alternate tree color", some of them are strange (just how the vanilla game does it) - Some screens are coded to change the "alternate tree color", some of them are strange (just how the vanilla game does it)
- Rocks and statues are unable to be made to have a different color - Rocks and statues are unable to be made to have a different color
Here is a map that shows all the [Bonk Locations](https://cdn.discordapp.com/attachments/1105770688649895968/1105770806769877072/bonkdrops.png?ex=66524790&is=6650f610&hm=7c16f009d514256d3fdd02667f9876fae4178ec2989e5f1e0cfd32c7207e144e&). FYI, the numbers indicate how many bonk items there. The stars with a green square are all Bonk Locations that are unlocked after you kill Aga 1. Here is a map that shows all the [Bonk Locations](https://zelda.codemann8.com/images/shared/bonkdrops.png). FYI, the numbers indicate how many bonk items there. The stars with a green square are all Bonk Locations that are unlocked after you kill Aga 1.
As far as map trackers, Bonk Locations are supported on `CodeTracker` when the Bonk Drops option is enabled. As far as map trackers, Bonk Locations are supported on `CodeTracker` when the Bonk Drops option is enabled.
@@ -282,7 +282,7 @@ This option shuffles the prize into a location somewhere within the dungeon that
### Randomized ### Randomized
This option freely shuffles the prizes throughout the world. While the dungeon prizes can end up anywhere, they still are assigned to a specific dungeon. When you defeat the boss of a certain dungeon, checking the map on the overworld will reveal the location WHERE you can find the prize, an example shown [here](https://cdn.discordapp.com/attachments/783989090017738753/1243840288867487754/prizemap-all.gif?ex=6652f00a&is=66519e8a&hm=a49ef2c84d9862349e331ae87c99c3ce34ae5cd0690073521423d7e61c5429dc&). Finding the map will still reveal WHAT the prize is. If you defeated a boss but haven't collected the map for that dungeon, the prize will be indicated by a red X, example shown [here](https://cdn.discordapp.com/attachments/783989090017738753/1243840289278263316/prizemap-boss.gif?ex=6652f00a&is=66519e8a&hm=f1d75388b2ca039f5c35f244109ff659b34235d6ce2f76516ad46f978ec49f91&). If you collected a map but haven't defeated the boss yet, the icon indicator on the map will be shown on the top edge (for LW dungeons) or the bottom edge (for DW dungeons), but it will show you WHAT the prize is for that dungeon, an example of that is shown [here](https://cdn.discordapp.com/attachments/783989090017738753/1243840289718669372/prizemap-map.gif?ex=6652f00a&is=66519e8a&hm=47fa004f493c63842bec3a54b7703d95d9a6a05067fa3fb539d48de9c0cb1698&). This option freely shuffles the prizes throughout the world. While the dungeon prizes can end up anywhere, they still are assigned to a specific dungeon. When you defeat the boss of a certain dungeon, checking the map on the overworld will reveal the location WHERE you can find the prize, an example shown [here](https://zelda.codemann8.com/images/shared/prizemap-all.gif). Finding the map will still reveal WHAT the prize is. If you defeated a boss but haven't collected the map for that dungeon, the prize will be indicated by a red X, example shown [here](https://zelda.codemann8.com/images/shared/prizemap-boss.gif). If you collected a map but haven't defeated the boss yet, the icon indicator on the map will be shown on the top edge (for LW dungeons) or the bottom edge (for DW dungeons), but it will show you WHAT the prize is for that dungeon, an example of that is shown [here](https://zelda.codemann8.com/images/shared/prizemap-map.gif).
- It is important to note that the overworld map check has changed: the numbered icons that are displayed are NO LONGER indicating the crystal number like they have in the past. They are now indicating the dungeon that it belongs to; a blue 1-3 indicates the 3 LW dungeons (EP, DP, and ToH) and a red 1-7 indicate the 7 DW dungeons - It is important to note that the overworld map check has changed: the numbered icons that are displayed are NO LONGER indicating the crystal number like they have in the past. They are now indicating the dungeon that it belongs to; a blue 1-3 indicates the 3 LW dungeons (EP, DP, and ToH) and a red 1-7 indicate the 7 DW dungeons
@@ -349,7 +349,7 @@ Here is a [Swapped ER Reference Sheet](http://zelda.codemann8.com/images/shared/
This is an entrance shuffle that only shuffles entrances within their respective `Districts` (See Below). Also, dropdowns and the entrance that a dropdown normally exits are NOT kept together; this also means that the Skull Woods entrances are no longer guaranteed to lead to Skull Woods. Also, since there is no district that can span multiple worlds, this is NOT a cross-world entrance mode. This is an entrance shuffle that only shuffles entrances within their respective `Districts` (See Below). Also, dropdowns and the entrance that a dropdown normally exits are NOT kept together; this also means that the Skull Woods entrances are no longer guaranteed to lead to Skull Woods. Also, since there is no district that can span multiple worlds, this is NOT a cross-world entrance mode.
Districts are a concept originally conceived by Aerinon in the Door Randomizer, where parts of the OW are split into areas and given a name. Here is a [District Map](https://cdn.discordapp.com/attachments/783989090017738753/1194615705027477534/districts.png?ex=66527f52&is=66512dd2&hm=6f29d8df27eea6a3489b3bb74381e02fb9706158c2f00bcef652f156a53c1268&) showing how they are split up. Districts are a concept originally conceived by Aerinon in the Door Randomizer, where parts of the OW are split into areas and given a name. Here is a [District Map](https://zelda.codemann8.com/images/shared/ow-districts-reference-sheet.png) showing how they are split up.
# Command Line Options # Command Line Options

5
Rom.py
View File

@@ -43,7 +43,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '096e6adebfa630e827c662f12f79b4cd' RANDOMIZERBASEHASH = '87be9d9bd56b6ad8e4b9697ecfc31841'
class JsonRom(object): class JsonRom(object):
@@ -507,6 +507,7 @@ def patch_rom(world, rom, player, team, is_mystery=False):
else: else:
flute_spots = world.owflutespots[player] flute_spots = world.owflutespots[player]
owFlags |= 0x0100 owFlags |= 0x0100
write_int16(rom, snes_to_pc(0x0AB7F7), 0xEAEA)
flute_writes = sorted([(f, flute_data[f][1]) for f in flute_spots], key = lambda f: f[1]) flute_writes = sorted([(f, flute_data[f][1]) for f in flute_spots], key = lambda f: f[1])
for o in range(0, len(flute_writes)): for o in range(0, len(flute_writes)):
@@ -729,7 +730,7 @@ def patch_rom(world, rom, player, team, is_mystery=False):
# fix hc big key problems (map and compass too) # fix hc big key problems (map and compass too)
if (world.doorShuffle[player] != 'vanilla' or world.dropshuffle[player] != 'none' if (world.doorShuffle[player] != 'vanilla' or world.dropshuffle[player] != 'none'
or world.pottery[player] not in ['none', 'cave']): or world.pottery[player] not in ['none', 'cave'] or world.prizeshuffle[player] != 'none'):
rom.write_byte(0x151f1, 2) rom.write_byte(0x151f1, 2)
rom.write_byte(0x15270, 2) rom.write_byte(0x15270, 2)
sanctuary = world.get_region('Sanctuary', player) sanctuary = world.get_region('Sanctuary', player)

View File

@@ -855,7 +855,7 @@ def global_rules(world, player):
for dungeon, info in dungeon_table.items(): for dungeon, info in dungeon_table.items():
if info.prize: if info.prize:
d_name = "Thieves' Town" if dungeon.startswith('Thieves') else dungeon d_name = "Thieves' Town" if dungeon.startswith('Thieves') else dungeon
for loc in [info.prize, f'{d_name} - Boss']: for loc in [f'{d_name} - Prize', f'{d_name} - Boss']:
add_mc_rule(loc) add_mc_rule(loc)
if world.doorShuffle[player] not in ['vanilla', 'basic']: if world.doorShuffle[player] not in ['vanilla', 'basic']:
add_mc_rule('Agahnim 1') add_mc_rule('Agahnim 1')

View File

@@ -78,6 +78,8 @@ org $8ab7af ;LDA $F2 : ORA $F0 : AND #$C0
jml OWFluteCancel2 : nop jml OWFluteCancel2 : nop
org $8ab90d ;JSL $02E99D org $8ab90d ;JSL $02E99D
jsl OWFluteCancel jsl OWFluteCancel
org $8ab816
JSL OWMapFluteCancelIcon
; allows Frog sprite to spawn in LW and also allows his friend to spawn in their house ; allows Frog sprite to spawn in LW and also allows his friend to spawn in their house
org $868a76 ; < 30a76 - sprite_prep.asm:785 (LDA $7EF3CA : AND.w #$40) org $868a76 ; < 30a76 - sprite_prep.asm:785 (LDA $7EF3CA : AND.w #$40)
@@ -334,6 +336,20 @@ OWFluteCancel2:
lda.b #$01 : sta.w RandoOverworldTargetEdge lda.b #$01 : sta.w RandoOverworldTargetEdge
+ rtl + rtl
} }
OWMapFluteCancelIcon:
{
STA.b Scrap0B : LDX.b #$10 ; what we wrote over
LDA.l OWFlags+1 : AND.b #$01 : BEQ .return
LDA.b GameSubMode : CMP.b #$0A : BNE .return
LDA.b FrameCounter : AND.b #$10 : BNE .return
LDA.b #$7E : STA.b Scrap0D
LDA.b #$34 : STA.b Scrap0C
STZ.b Scrap0B
LDA.b Scrap0E : CLC : ADC.b #$04 : STA.b Scrap0E
LDA.b Scrap0F : CLC : ADC.b #$04 : STA.b Scrap0F
.return
RTL
}
OWSmithAccept: OWSmithAccept:
{ {
lda.l FollowerIndicator : cmp.b #$07 : beq + lda.l FollowerIndicator : cmp.b #$07 : beq +

Binary file not shown.

View File

@@ -10,6 +10,7 @@ settings:
dropshuffle: keys dropshuffle: keys
experimental: true experimental: true
goal: ganon goal: ganon
prizeshuffle: dungeon
hints: true hints: true
intensity: 3 intensity: 3
overworld_map: compass overworld_map: compass

View File

@@ -148,6 +148,10 @@
none: 1 none: 1
mapcompass: 1 mapcompass: 1
dungeon: 1 dungeon: 1
prize_shuffle:
none: 1
dungeon: 1
wild: 1
dungeon_items: dungeon_items:
standard: 10 standard: 10
mc: 3 mc: 3

View File

@@ -0,0 +1,82 @@
meta:
players: 1
ow-edges:
1:
two-way:
Lost Woods NW: Master Sword Meadow SC
Lumberjack SW*: Mountain Pass NW*
Dark Lumberjack SW*: Bumper Cave NW*
West Death Mountain EN*: East Death Mountain WN*
West Death Mountain ES*: East Death Mountain WS*
West Dark Death Mountain EN*: East Dark Death Mountain WN*
West Dark Death Mountain ES*: East Dark Death Mountain WS*
East Death Mountain EN*: Death Mountain TR Pegs WN*
East Dark Death Mountain EN*: Turtle Rock WN*
Zora Waterfall NE: Zoras Domain SW
Lost Woods Pass SW*: Kakariko NW*
Lost Woods Pass SE*: Kakariko NC*
Skull Woods Pass SW*: Village of Outcasts NW*
Skull Woods Pass SE*: Village of Outcasts NC*
Kakariko Fortune SC*: Kakariko NE*
Dark Fortune SC*: Village of Outcasts NE*
Kakariko Pond EN*: Sanctuary WN*
Kakariko Pond ES*: Sanctuary WS*
Kakariko Pond SW*: Forgotten Forest NW*
Kakariko Pond SE*: Forgotten Forest NE*
Outcast Pond EN*: Dark Chapel WN*
Outcast Pond ES*: Dark Chapel WS*
Outcast Pond SW*: Shield Shop NW*
Outcast Pond SE*: Shield Shop NE*
Graveyard EC*: River Bend WC*
Dark Graveyard EC*: Qirn Jump WC*
River Bend SW*: Wooden Bridge NW*
River Bend SC*: Wooden Bridge NC*
River Bend SE*: Wooden Bridge NE*
Qirn Jump SW*: Broken Bridge NW*
Qirn Jump SC*: Broken Bridge NC*
Qirn Jump SE*: Broken Bridge NE*
Potion Shop EN*: Zora Approach WN*
Potion Shop EC*: Zora Approach WC*
Dark Witch EN*: Catfish Approach WN*
Dark Witch EC*: Catfish Approach WC*
Kakariko SE*: Kakariko Suburb NE*
Village of Outcasts SE*: Frog NE*
Forgotten Forest ES: Hyrule Castle WN
Hyrule Castle ES*: Sand Dunes WN*
Hyrule Castle SW*: Central Bonk Rocks NW*
Hyrule Castle SE*: Links House NE*
Pyramid ES*: Dark Dunes WN*
Pyramid SW*: Dark Bonk Rocks NW*
Pyramid SE*: Big Bomb Shop NE*
Eastern Palace SW*: Tree Line NW*
Eastern Palace SE*: Eastern Nook NE*
Palace of Darkness SW*: Dark Tree Line NW*
Palace of Darkness SE*: Palace of Darkness Nook NE*
Sand Dunes SC*: Stone Bridge NC*
Dark Dunes SC*: Hammer Bridge NC*
Maze Race ES*: Kakariko Suburb WS*
Dig Game EC: Frog WC
Dig Game ES*: Frog WS*
Links House ES*: Stone Bridge WS*
Big Bomb Shop ES*: Hammer Bridge WS*
Stone Bridge WC: Hobo EC
Flute Boy Approach EC*: C Whirlpool WC*
Stumpy Approach EC*: Dark C Whirlpool WC*
C Whirlpool SC*: Dam NC*
Dark C Whirlpool SC*: Swamp NC*
Statues SC*: South Pass NC*
Hype Cave SC*: Dark South Pass NC*
Lake Hylia WS*: South Pass ES*
Lake Hylia EC*: Octoballoon WC*
Lake Hylia ES*: Octoballoon WS*
Ice Lake WS*: Dark South Pass ES*
Ice Lake EC*: Bomber Corner WC*
Ice Lake ES*: Bomber Corner WS*
Ice Cave SW*: Octoballoon NW*
Ice Cave SE*: Octoballoon NE*
Shopping Mall SW*: Bomber Corner NW*
Shopping Mall SE*: Bomber Corner NE*
Desert Pass EC*: Dam WC*
Desert Pass ES*: Dam WS*
Swamp Nook EC*: Swamp WC*
Swamp Nook ES*: Swamp WS*

View File

@@ -304,9 +304,12 @@ def do_main_shuffle(entrances, exits, avail, mode_def):
if not avail.world.is_bombshop_start(avail.player): if not avail.world.is_bombshop_start(avail.player):
bomb_shop = 'Big Bomb Shop' bomb_shop = 'Big Bomb Shop'
if bomb_shop in rem_exits: if bomb_shop in rem_exits:
bomb_shop_options = [x for x in rem_entrances] bomb_shop_forbidden = []
if avail.world.logic[avail.player] in ['noglitches', 'minorglitches']:
bomb_shop_forbidden.append('Pyramid Fairy')
if avail.world.is_tile_swapped(0x03, avail.player): if avail.world.is_tile_swapped(0x03, avail.player):
bomb_shop_options = [x for x in bomb_shop_options if x not in ['Spectacle Rock Cave', 'Spectacle Rock Cave (Bottom)']] bomb_shop_forbidden.extend(['Spectacle Rock Cave', 'Spectacle Rock Cave (Bottom)'])
bomb_shop_options = [x for x in rem_entrances if x not in bomb_shop_forbidden]
if avail.swapped and len(bomb_shop_options) > 1: if avail.swapped and len(bomb_shop_options) > 1:
bomb_shop_options = [x for x in bomb_shop_options if x != 'Big Bomb Shop'] bomb_shop_options = [x for x in bomb_shop_options if x != 'Big Bomb Shop']

View File

@@ -112,7 +112,7 @@ if __name__ == "__main__":
test_suites = {} test_suites = {}
# not sure if it supports subdirectories properly yet # not sure if it supports subdirectories properly yet
for root, dirnames, filenames in os.walk(os.path.join("test","suite")): for root, dirnames, filenames in os.walk(os.path.join("test","owrsuite")):
test_suites[root] = fnmatch.filter(filenames, '*.yaml') test_suites[root] = fnmatch.filter(filenames, '*.yaml')
args = argparse.Namespace() args = argparse.Namespace()
@@ -148,5 +148,5 @@ if __name__ == "__main__":
print(f"Success: {num_success}/{num_total}") print(f"Success: {num_success}/{num_total}")
# print(results) # print(results)
if (num_errors/num_total) > (num_success/num_total): # if (num_errors/num_total) > (num_success/num_total):
exit(1) # exit(1)

View File

@@ -0,0 +1,8 @@
# Even though Lamp is Flipper-locked, this logic considers that a key could be wasted in the dark in mire
# Only fire locked mire is off limits
meta:
players: 1
settings:
1:
key_logic_algorithm: partial
keysanity: true