Skip to content

Commit

Permalink
Merge pull request #401 from CovenEsme/sky-keep-dungeon-setting
Browse files Browse the repository at this point in the history
Sky Keep dungeon setting
  • Loading branch information
CovenEsme authored Jul 24, 2024
2 parents 0d8b95a + f147fc3 commit 89a9642
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 52 deletions.
19 changes: 19 additions & 0 deletions data/patches/eventpatches.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,25 @@
param2: 3 # item
next: -1
param3: 9
- name: Add flow for Sky Keep goal location sign
type: entryadd
entry:
name: "107_99"
value: Sky Keep goal location sign start
- name: Sky Keep goal location sign start
type: flowadd
flow:
type: start
next: Show Sky Keep goal location sign text
- name: Sky Keep goal location sign text with replaced text
type: textadd
- name: Show Sky Keep goal location sign text
type: flowadd
flow:
type: type1
next: -1
param3: 88
param4: Sky Keep goal location sign text with replaced text

108-ShinkanA:
- name: Owlans Shield
Expand Down
13 changes: 13 additions & 0 deletions data/patches/stagepatches.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4771,6 +4771,19 @@ D003_7: # Sky Keep Entrance Room
layer: 0
room: 0
objtype: OBJ
- name: Add stone statue to tell goal location
type: objadd
layer: 0
room: 0
objtype: OBJ
object:
params1: 0xFFFF2A2F # entrypoint 107_99
params2: 0xFFFFFFFF
posx: 650
posy: 0
posz: 2070
angley: 0xC000
name: KanbanS
- name: Remove bars opening cs
type: objpatch
id: 0xFC16
Expand Down
14 changes: 12 additions & 2 deletions data/settings_list.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -525,9 +525,19 @@
default_option: 2
pretty_name: Required Dungeons
pretty_options:
- 0-6
- 0-7
options:
- 0-7: "Choose how many dungeons will have required items on their dungeon completion checks. Triforces, then swords, then other progress items are chosen, in this order."

- name: dungeons_include_sky_keep
default_option: "off"
pretty_name: Include Sky Keep as a Dungeon
pretty_options:
- "Off"
- "On"
options:
- 0-6: "Choose how many dungeons will have required items on their dungeon completion checks. Triforces, then swords, then other progress items are chosen, in this order."
- "off": "Only the 6 main dungeons may be selected as required dungeons."
- "on": "Sky Keep may be selected as a required dungeon needed to beat the seed. If selected, one of the \"Sacred Power\" locations will be chosen as the \"Goal Location\" containing an important item (shown on a stone tablet in the 1st room of Sky Keep)."

- name: empty_unrequired_dungeons
tracker_important: true
Expand Down
19 changes: 17 additions & 2 deletions data/text_data/en_US.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5547,16 +5547,19 @@
standard: Sky Keep - Sacred Power of Din
pretty: Sky Keep - Sacred Power of Din
cryptic: the <r<power of a goddess>>
goal_name: a Sacred Power

- name: Sky Keep - Sacred Power of Nayru
standard: Sky Keep - Sacred Power of Nayru
pretty: Sky Keep - Sacred Power of Nayru
cryptic: the <r<wisdom of a goddess>>
goal_name: a Sacred Power

- name: Sky Keep - Sacred Power of Farore
standard: Sky Keep - Sacred Power of Farore
pretty: Sky Keep - Sacred Power of Farore
cryptic: the <r<courage of a goddess>>
goal_name: a Sacred Power

- name: The Goddess's Silent Realm - Stamina Fruit on Knight Academy Ledge
standard: The Goddess's Silent Realm - Stamina Fruit on Knight Academy Ledge
Expand Down Expand Up @@ -5870,6 +5873,18 @@
- name: FFW Bucha stay text
standard: "Talk to me again if you change your\nmind, kewwwwww.<action0 \x0c>"
- name: Sky Keep No Goal Location Text
standard: "Hero of the Goddess!\nSeek now the exit."
- name: Sky Keep Goal Location Sacred Power of Farore Text
standard: "Hero of the Goddess!\nSeek now the <g<Sacred Power of Farore>>."
- name: Sky Keep Goal Location Sacred Power of Nayru Text
standard: "Hero of the Goddess!\nSeek now the <b<Sacred Power of Nayru>>."
- name: Sky Keep Goal Location Sacred Power of Din Text
standard: "Hero of the Goddess!\nSeek now the <r<Sacred Power of Din>>."
# Fi text
- name: No Fi Hints Text
standard: "Master, I unfortunately have <r<no hints>> for you."
Expand All @@ -5890,13 +5905,13 @@
standard: "Welcome to your new adventure, Master. I have\n<r<important information>> about your journey."
- name: No Required Dungeons Text
standard: "I detect no dungeons with strong readings."
standard: "I detect <r<no dungeons>> with strong readings."
- name: Some Required Dungeons Text
standard: "I detect strong readings in the following dungeons:\n{dungeon_text}"
- name: All Required Dungeons Text
standard: "I detect many strong readings. I recommend you\ncomplete all the dungeons."
standard: "I detect many strong readings. I recommend you\n<r<complete all the dungeons>>."
- name: Fi Information Text Patch
standard: "Yes, Master. What information do you seek?\n[1]Hints[2]Notes[3]Required Dungeons[4-]Never mind."
Expand Down
3 changes: 0 additions & 3 deletions data/world/Sky Keep.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@


- name: SK Sacred Power of Farore Room
dungeon: Sky Keep
exits:
SK Ancient Cistern Room South: Nothing
locations:
Expand All @@ -127,7 +126,6 @@


- name: SK Sacred Power of Din Room
dungeon: Sky Keep
exits:
SK Fire Sanctuary Room End Platform: Nothing
locations:
Expand All @@ -147,7 +145,6 @@


- name: SK Sacred Power of Nayru Room
dungeon: Sky Keep
exits:
SK Sandship Room West: Nothing
locations:
Expand Down
13 changes: 10 additions & 3 deletions gui/ui/main.ui
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<enum>QTabWidget::TabShape::Rounded</enum>
</property>
<property name="currentIndex">
<number>9</number>
<number>1</number>
</property>
<widget class="QWidget" name="getting_started_tab">
<property name="sizePolicy">
Expand Down Expand Up @@ -893,6 +893,13 @@
</item>
</layout>
</item>
<item>
<widget class="RandoTriStateCheckBox" name="setting_dungeons_include_sky_keep">
<property name="text">
<string>Include Sky Keep as a Dungeon</string>
</property>
</widget>
</item>
<item>
<widget class="RandoTriStateCheckBox" name="setting_empty_unrequired_dungeons">
<property name="text">
Expand Down Expand Up @@ -3970,8 +3977,8 @@ QPushButton {
<rect>
<x>0</x>
<y>0</y>
<width>546</width>
<height>340</height>
<width>100</width>
<height>30</height>
</rect>
</property>
<property name="maximumSize">
Expand Down
36 changes: 21 additions & 15 deletions gui/ui/ui_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'main.ui'
##
## Created by: Qt User Interface Compiler version 6.7.1
## Created by: Qt User Interface Compiler version 6.6.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
Expand Down Expand Up @@ -609,6 +609,11 @@ def setupUi(self, main_window):

self.verticalLayout_13.addLayout(self.required_dungeons_layout)

self.setting_dungeons_include_sky_keep = RandoTriStateCheckBox(self.beat_the_game_group_box)
self.setting_dungeons_include_sky_keep.setObjectName(u"setting_dungeons_include_sky_keep")

self.verticalLayout_13.addWidget(self.setting_dungeons_include_sky_keep)

self.setting_empty_unrequired_dungeons = RandoTriStateCheckBox(self.beat_the_game_group_box)
self.setting_empty_unrequired_dungeons.setObjectName(u"setting_empty_unrequired_dungeons")

Expand Down Expand Up @@ -825,8 +830,8 @@ def setupUi(self, main_window):

self.line = QFrame(self.open_dungeons_group_box)
self.line.setObjectName(u"line")
self.line.setFrameShape(QFrame.Shape.HLine)
self.line.setFrameShadow(QFrame.Shadow.Sunken)
self.line.setFrameShape(QFrame.HLine)
self.line.setFrameShadow(QFrame.Sunken)

self.verticalLayout_25.addWidget(self.line)

Expand Down Expand Up @@ -1034,8 +1039,8 @@ def setupUi(self, main_window):

self.mixed_entrance_pools_hline = QFrame(self.mixed_entrance_pools_group_box)
self.mixed_entrance_pools_hline.setObjectName(u"mixed_entrance_pools_hline")
self.mixed_entrance_pools_hline.setFrameShape(QFrame.Shape.HLine)
self.mixed_entrance_pools_hline.setFrameShadow(QFrame.Shadow.Sunken)
self.mixed_entrance_pools_hline.setFrameShape(QFrame.HLine)
self.mixed_entrance_pools_hline.setFrameShadow(QFrame.Sunken)

self.verticalLayout_28.addWidget(self.mixed_entrance_pools_hline)

Expand Down Expand Up @@ -2073,8 +2078,8 @@ def setupUi(self, main_window):

self.player_cosmetics_hline = QFrame(self.player_cosmetics_group_box)
self.player_cosmetics_hline.setObjectName(u"player_cosmetics_hline")
self.player_cosmetics_hline.setFrameShape(QFrame.Shape.HLine)
self.player_cosmetics_hline.setFrameShadow(QFrame.Shadow.Sunken)
self.player_cosmetics_hline.setFrameShape(QFrame.HLine)
self.player_cosmetics_hline.setFrameShadow(QFrame.Sunken)

self.verticalLayout_37.addWidget(self.player_cosmetics_hline)

Expand Down Expand Up @@ -2165,8 +2170,8 @@ def setupUi(self, main_window):

self.utils_hline = QFrame(self.file_setup_group_box)
self.utils_hline.setObjectName(u"utils_hline")
self.utils_hline.setFrameShape(QFrame.Shape.HLine)
self.utils_hline.setFrameShadow(QFrame.Shadow.Sunken)
self.utils_hline.setFrameShape(QFrame.HLine)
self.utils_hline.setFrameShadow(QFrame.Sunken)

self.verticalLayout_31.addWidget(self.utils_hline)

Expand All @@ -2192,8 +2197,8 @@ def setupUi(self, main_window):

self.utils_hline_2 = QFrame(self.file_setup_group_box)
self.utils_hline_2.setObjectName(u"utils_hline_2")
self.utils_hline_2.setFrameShape(QFrame.Shape.HLine)
self.utils_hline_2.setFrameShadow(QFrame.Shadow.Sunken)
self.utils_hline_2.setFrameShape(QFrame.HLine)
self.utils_hline_2.setFrameShadow(QFrame.Sunken)

self.verticalLayout_31.addWidget(self.utils_hline_2)

Expand Down Expand Up @@ -2227,8 +2232,8 @@ def setupUi(self, main_window):

self.utils_hline_3 = QFrame(self.file_setup_group_box)
self.utils_hline_3.setObjectName(u"utils_hline_3")
self.utils_hline_3.setFrameShape(QFrame.Shape.HLine)
self.utils_hline_3.setFrameShadow(QFrame.Shadow.Sunken)
self.utils_hline_3.setFrameShape(QFrame.HLine)
self.utils_hline_3.setFrameShadow(QFrame.Sunken)

self.verticalLayout_31.addWidget(self.utils_hline_3)

Expand Down Expand Up @@ -2658,7 +2663,7 @@ def setupUi(self, main_window):
self.tracker_locations_scroll_area.setWidgetResizable(True)
self.tracker_locations_scroll_widget = QWidget()
self.tracker_locations_scroll_widget.setObjectName(u"tracker_locations_scroll_widget")
self.tracker_locations_scroll_widget.setGeometry(QRect(0, 0, 546, 340))
self.tracker_locations_scroll_widget.setGeometry(QRect(0, 0, 100, 30))
self.tracker_locations_scroll_widget.setMaximumSize(QSize(546, 16777215))
self.tracker_locations_scroll_layout = QHBoxLayout(self.tracker_locations_scroll_widget)
self.tracker_locations_scroll_layout.setSpacing(0)
Expand Down Expand Up @@ -2801,7 +2806,7 @@ def setupUi(self, main_window):

self.retranslateUi(main_window)

self.tab_widget.setCurrentIndex(9)
self.tab_widget.setCurrentIndex(1)


QMetaObject.connectSlotsByName(main_window)
Expand Down Expand Up @@ -2860,6 +2865,7 @@ def retranslateUi(self, main_window):
self.beat_the_game_group_box.setTitle(QCoreApplication.translate("main_window", u"Beat the Game", None))
self.got_sword_requirement_label.setText(QCoreApplication.translate("main_window", u"Gate of Time Sword Requirement", None))
self.required_dungeons_label.setText(QCoreApplication.translate("main_window", u"Required Dungeons", None))
self.setting_dungeons_include_sky_keep.setText(QCoreApplication.translate("main_window", u"Include Sky Keep as a Dungeon", None))
self.setting_empty_unrequired_dungeons.setText(QCoreApplication.translate("main_window", u"Barren Unrequired Dungeons", None))
self.setting_skip_horde.setText(QCoreApplication.translate("main_window", u"Skip The Horde Fight", None))
self.setting_skip_g3.setText(QCoreApplication.translate("main_window", u"Skip Ghirahim 3 Fight", None))
Expand Down
7 changes: 7 additions & 0 deletions logic/dungeon.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ def __str__(self) -> str:
return self.name

def should_be_barren(self) -> bool:
# If Sky Keep is explicitly disabled it should always be barren regardless of other settings.
if (
self.name == "Sky Keep"
and self.world.setting("dungeons_include_sky_keep") == "off"
):
return True

return (
not self.required
and self.world.setting("empty_unrequired_dungeons") == "on"
Expand Down
6 changes: 5 additions & 1 deletion logic/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,11 @@ def all_logic_satisfied(worlds: list["World"], item_pool: Counter[Item] = {}) ->
accessible_goal_locations = [
l
for l in world.location_table.values()
if l.is_goal_location and not l.name.startswith("Sky Keep")
if l.is_goal_location
and (
world.setting("dungeons_include_sky_keep") == "on"
or not l.name.startswith("Sky Keep")
)
]
if (
world.get_game_winning_item() not in search.owned_items
Expand Down
27 changes: 13 additions & 14 deletions logic/world.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,9 +304,13 @@ def resolve_random_settings(self) -> None:
setting.resolve_if_random()

def resolve_conflicting_settings(self) -> None:
# Resolve any conflicting settings here if we ever
# find any
pass
if (
self.setting("required_dungeons") == "7"
and self.setting("dungeons_include_sky_keep") == "off"
):
raise ValueError(
"Cannot require 7 dungeons when Sky Keep is not a dungeon. Please either reduce the required dungeon count or enable Sky Keep to be a required dungeon."
)

def place_hardcoded_items(self) -> None:
defeat_demise = self.get_location("Hylia's Realm - Defeat Demise")
Expand Down Expand Up @@ -413,18 +417,17 @@ def choose_required_dungeons(self) -> None:
num_required_dungeons = self.setting("required_dungeons").value_as_number()
num_chosen_dungeons = 0

dungeons = [
d
for d in self.dungeons.values()
if d.goal_location and d.name != "Sky Keep"
]
dungeons = [d for d in self.dungeons.values() if d.goal_location]

# Disable the Eldin Pillar -> Fire Sanctuary entrance so that
# it doesn't erroneously give "access" to fire sanctuary in no logic
self.get_entrance("Eldin Pillar -> Inside the Fire Sanctuary Statue").disable()

# Also disable Sky Keep's entrance if it's not required
sky_keep = self.get_dungeon("Sky Keep")
sky_keep.starting_entrance.disabled = sky_keep.should_be_barren()
if self.setting("dungeons_include_sky_keep") == "off":
sky_keep = self.get_dungeon("Sky Keep")
sky_keep.starting_entrance.disabled = True
dungeons.remove(sky_keep)

random.shuffle(dungeons)
item_pool = get_complete_item_pool(self.worlds)
Expand Down Expand Up @@ -576,10 +579,6 @@ def set_nonprogress_locations(self):
):
location.progression = False

# Sky Keep will never be a required dungeon with empty unrequired dungeons
if self.setting("empty_unrequired_dungeons") == "on":
self.dungeons["Sky Keep"].required = False

# Set beedle's shop items as nonprogress if they can only contain junk
if self.setting("beedle_shop_shuffle") == "junk_only":
for location in self.location_table.values():
Expand Down
Loading

0 comments on commit 89a9642

Please sign in to comment.