Skip to content

Commit

Permalink
add toggle for sphere tracking, fix bug with autosave exception handling
Browse files Browse the repository at this point in the history
  • Loading branch information
YourAverageLink committed May 31, 2024
1 parent 3fe5a20 commit d1cc067
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 21 deletions.
11 changes: 7 additions & 4 deletions gui/components/tracker_inventory_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def __init__(
self.world: World = None
self.sphere_tracked_items: dict[Location, str] = {}
self.inventory: Counter[Item]
self.allow_sphere_tracking: bool = False
assert len(self.items) == len(self.filenames)

self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
Expand Down Expand Up @@ -138,7 +139,7 @@ def add_forbidden_state(self, state: int) -> None:
self.forbidden_states.add(state)

def mouseReleaseEvent(self, ev: QMouseEvent) -> None:
should_sphere_track = True
should_sphere_track = self.allow_sphere_tracking
if ev.button() == QtCore.Qt.LeftButton:
first_iteration = True
while first_iteration or self.state in self.forbidden_states:
Expand Down Expand Up @@ -171,9 +172,11 @@ def mouseReleaseEvent(self, ev: QMouseEvent) -> None:
return super().mouseReleaseEvent(ev)

def mouseMoveEvent(self, ev: QMouseEvent) -> None:
self.calculate_tooltip()
coords = self.mapToGlobal(QPoint(0, 0)) + QPoint(-60, self.height() * 3 / 4)
QToolTip.showText(coords, self.tooltip, self)
if self.allow_sphere_tracking:
self.calculate_tooltip()
coords = self.mapToGlobal(QPoint(0, 0)) + QPoint(-60, self.height() * 3 / 4)
QToolTip.showText(coords, self.tooltip, self)

self.update_hover_text()

return super().mouseMoveEvent(ev)
Expand Down
29 changes: 24 additions & 5 deletions gui/components/tracker_location_label.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ class TrackerLocationLabel(QLabel):
clicked = Signal(str, Location)

def __init__(
self, location_: Location, search: Search, parent_area_button_
self,
location_: Location,
search: Search,
parent_area_button_,
allow_sphere_tracking_,
) -> None:
super().__init__()
self.location = location_
Expand All @@ -36,24 +40,37 @@ def __init__(
self.setWordWrap(True)
self.recent_search: Search = search
self.parent_area_button = parent_area_button_
self.allow_sphere_tracking: bool = allow_sphere_tracking_

# Chop off the location's area in the name if it's the same
# as the region it's in
if self.location.name.startswith(self.parent_area_button.area):
self.setText(
f"[{'?' if self.location.sphere == None else self.location.sphere}] "
(
f"[{'?' if self.location.sphere == None else self.location.sphere}] "
if self.allow_sphere_tracking
else ""
)
+ self.location.name.replace(f"{self.parent_area_button.area} - ", "")
)
elif self.parent_area_button.alias and self.location.name.startswith(
self.parent_area_button.alias
):
self.setText(
f"[{'?' if self.location.sphere == None else self.location.sphere}] "
(
f"[{'?' if self.location.sphere == None else self.location.sphere}] "
if self.allow_sphere_tracking
else ""
)
+ self.location.name.replace(f"{self.parent_area_button.alias} - ", "")
)
else:
self.setText(
f"[{'?' if self.location.sphere == None else self.location.sphere}] "
(
f"[{'?' if self.location.sphere == None else self.location.sphere}] "
if self.allow_sphere_tracking
else ""
)
+ self.location.name
)

Expand All @@ -77,7 +94,9 @@ def __init__(
self.pixmap.load(
(TRACKER_ASSETS_PATH / "dungeons" / "small_key.png").as_posix()
)
elif (image := self.location.tracked_item_image) is not None:
elif (
image := self.location.tracked_item_image
) is not None and self.allow_sphere_tracking:
self.pixmap.load((TRACKER_ASSETS_PATH / image).as_posix())
else:
has_icon = False
Expand Down
35 changes: 35 additions & 0 deletions gui/components/tracker_toggle_st_button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from PySide6.QtWidgets import QPushButton, QSizePolicy, QToolTip
from PySide6.QtGui import QFontDatabase, QCursor, QMouseEvent
from PySide6 import QtCore
from PySide6.QtCore import Signal, QPoint

from filepathconstants import TRACKER_ASSETS_PATH


class TrackerToggleSTButton(QPushButton):

left_clicked = Signal()
right_clicked = Signal()

def __init__(self, parent_) -> None:
super().__init__(parent_)
self.setText("Enable Sphere Tracking")
self.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
self.setStyleSheet(
"QToolTip { color: white; background-color: black; border-image: none; border-color: white; }"
)
self.setMouseTracking(True)

def mouseMoveEvent(self, ev: QMouseEvent) -> None:
coords = self.mapToGlobal(QPoint(0, 0)) + QPoint(100, self.height() / 4)
QToolTip.showText(coords, "Right-click for info", self)

return super().mouseMoveEvent(ev)

def mouseReleaseEvent(self, ev: QMouseEvent) -> None:
if ev.button() == QtCore.Qt.LeftButton:
self.left_clicked.emit()
elif ev.button() == QtCore.Qt.RightButton:
self.right_clicked.emit()

return super().mouseReleaseEvent(ev)
98 changes: 86 additions & 12 deletions gui/tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from gui.components.tracker_show_locations_button import TrackerShowLocationsButton
from gui.components.tracker_tablet_widget import TrackerTabletWidget
from gui.components.tracker_hint_label import TrackerHintLabel
from gui.components.tracker_toggle_st_button import TrackerToggleSTButton
from gui.dialogs.fi_info_dialog import FiInfoDialog
from gui.dialogs.fi_question_dialog import FiQuestionDialog

Expand Down Expand Up @@ -74,6 +75,7 @@ def __init__(self, main: "Main", ui: "Ui_main_window") -> None:
self.items_on_mark: dict[Location, Item] = {}
self.own_dungeon_key_locations: list[tuple[Item, list[Location]]] = []
self.sphere_tracked_items: dict[Location, str]
self.allow_sphere_tracking: bool = False

# Holds which entrance is connected to which target
self.connected_entrances: dict[Entrance, Entrance] = {}
Expand Down Expand Up @@ -129,13 +131,13 @@ def __init__(self, main: "Main", ui: "Ui_main_window") -> None:
try:
self.load_tracker_autosave()
except Exception as e:
self.fi_dialog = FiInfoDialog(self.main)
self.fi_dialog.show_dialog(
self.main.fi_info_dialog.show_dialog(
"Error loading tracker autosave",
"There was an error loading the autosave from the tracker.<br>"
+ f"{e}.<br>"
+ "The tracker must be loaded from scratch.",
)
self.initialize_tracker_world()

self.ui.start_new_tracker_button.clicked.connect(
self.on_start_new_tracker_button_clicked
Expand All @@ -155,6 +157,12 @@ def __init__(self, main: "Main", ui: "Ui_main_window") -> None:
self.cancel_sphere_tracking
)
self.ui.set_hints_button.clicked.connect(self.show_hint_options)
self.ui.toggle_sphere_tracking_button.left_clicked.connect(
self.toggle_sphere_tracking
)
self.ui.toggle_sphere_tracking_button.right_clicked.connect(
self.display_sphere_tracking_popup
)

self.update_statistics()

Expand Down Expand Up @@ -770,6 +778,12 @@ def initialize_tracker_world(
self.inventory[self.world.get_item(GRATITUDE_CRYSTAL_PACK)] += packs_to_add
self.inventory[self.world.get_item(GRATITUDE_CRYSTAL)] = 0

# Remember if the user was tracking spheres
self.allow_sphere_tracking |= autosave.get("allow_sphere_tracking", False)

if self.allow_sphere_tracking:
self.ui.toggle_sphere_tracking_button.setText("Disable Sphere Tracking")

# Apply starting inventory to inventory buttons and assign world
for inventory_button in self.ui.tracker_tab.findChildren(
TrackerInventoryButton
Expand All @@ -779,6 +793,7 @@ def initialize_tracker_world(
inventory_button.state = 0
inventory_button.forbidden_states.clear()
inventory_button.sphere_tracked_items = self.sphere_tracked_items
inventory_button.allow_sphere_tracking = self.allow_sphere_tracking
for item in self.inventory.elements():
if item.name in inventory_button.items:
inventory_button.add_forbidden_state(inventory_button.state)
Expand Down Expand Up @@ -940,7 +955,10 @@ def show_area_locations(self, area_name: str) -> None:
for i, loc in enumerate(locations):

location_label = TrackerLocationLabel(
loc, area_button.recent_search, area_button
loc,
area_button.recent_search,
area_button,
self.allow_sphere_tracking,
)
# Split locations evenly among the left and right layouts
if i < len(locations) / 2:
Expand Down Expand Up @@ -1169,17 +1187,20 @@ def on_click_location_label(self, location_area: str, location: Location) -> Non
if not location.marked:
# stop sphere tracking if unmarking a location
self.last_checked_location = None
if location.tracked_item is not None:
if location.tracked_item is not None and self.allow_sphere_tracking:
location.tracked_item = None
location.tracked_item_image = None
del self.sphere_tracked_items[location]
# update the location list to remove the item
self.show_area_locations(location_area)
# only start sphere-tracking "normal" locations
elif not (
location.has_vanilla_goddess_cube()
or location.has_vanilla_gratitude_crystal()
or location.is_gossip_stone()
elif (
not (
location.has_vanilla_goddess_cube()
or location.has_vanilla_gratitude_crystal()
or location.is_gossip_stone()
)
and self.allow_sphere_tracking
):
self.last_checked_location = location
self.update_tracker()
Expand Down Expand Up @@ -1376,8 +1397,9 @@ def update_tracker(self) -> None:
self.show_area_location_info(location_label_area_name)
self.autosave_tracker()
self.update_statistics()
self.update_spheres()
self.show_sphere_tracking_info()
if self.allow_sphere_tracking:
self.update_spheres()
self.show_sphere_tracking_info()

def update_areas_locations(self) -> None:
# Clear all locations before reassigning
Expand Down Expand Up @@ -1442,6 +1464,7 @@ def autosave_tracker(self) -> None:
for dungeon in self.ui.tracker_tab.findChildren(TrackerDungeonLabel)
if dungeon.active
]
autosave["allow_sphere_tracking"] = self.allow_sphere_tracking
autosave["sphere_tracked_items"] = {
loc.name: (item_name, loc.tracked_item_image)
for loc, item_name in self.sphere_tracked_items.items()
Expand Down Expand Up @@ -1553,7 +1576,6 @@ def on_check_all_in_logic_clicked(self):
self.handle_check_all(True, True)

def on_uncheck_all_clicked(self):

self.handle_check_all(False, False)

def handle_check_all(self, in_logic_only=False, check=True):
Expand All @@ -1562,7 +1584,7 @@ def handle_check_all(self, in_logic_only=False, check=True):
location_list = self.last_opened_region.get_available_locations()
else:
location_list = self.last_opened_region.get_included_locations()
if check == False:
if check == False and self.allow_sphere_tracking:
# untrack all sphere-tracked items in this area
self.last_checked_location = None
for location in location_list:
Expand Down Expand Up @@ -1617,6 +1639,7 @@ def show_sphere_tracking_info(self):
if self.last_checked_location is not None:
self.ui.tracker_sphere_tracking_label.setVisible(True)
self.ui.cancel_sphere_tracking_button.setVisible(True)
self.ui.toggle_sphere_tracking_button.setVisible(False)
item = self.last_checked_location.tracked_item
self.ui.tracker_sphere_tracking_label.setText(
self.last_checked_location.name
Expand All @@ -1626,6 +1649,7 @@ def show_sphere_tracking_info(self):
else:
self.ui.tracker_sphere_tracking_label.setVisible(False)
self.ui.cancel_sphere_tracking_button.setVisible(False)
self.ui.toggle_sphere_tracking_button.setVisible(True)

def cancel_sphere_tracking(self):
self.last_checked_location = None
Expand Down Expand Up @@ -1699,3 +1723,53 @@ def on_click_hint_label(self, hint: str, area: TrackerArea):
area.hints.add(hint)

self.show_area_locations(area.area)

def toggle_sphere_tracking(self):
self.allow_sphere_tracking = not self.allow_sphere_tracking
for inventory_button in self.ui.tracker_tab.findChildren(
TrackerInventoryButton
):
inventory_button.allow_sphere_tracking = self.allow_sphere_tracking
if self.allow_sphere_tracking:
self.ui.toggle_sphere_tracking_button.setText("Disable Sphere Tracking")
self.update_spheres()
else:
self.ui.toggle_sphere_tracking_button.setText("Enable Sphere Tracking")
self.cancel_sphere_tracking()
if self.last_opened_region is not None:
self.show_area_locations(self.last_opened_region.area)

self.update_tracker()

def display_sphere_tracking_popup(self):
self.main.fi_info_dialog.show_dialog(
"How to use Sphere Tracking",
"""
<b>What is sphere tracking?</b><br><br>
Sphere tracking is a feature of the tracker
that allows you to keep track of where you found
certain items, and the 'sphere' of logic that each
check is in. A sphere describes the rough number of
'steps' to take or items to find to access a specific
check. For example, locations avaiable from the start
are listed as 'Sphere 0' locations, and any locations
unlocked by items found in sphere 0 are sphere 1
locations, and so on.<br><br>
(It's important to note that SSHD Randomizer's logic
does not inherently account for spheres; they are
merely a helpful way to visualize progression and
requirements throughout a seed.)<br><br>
<b>Instructions</b><br><br>
To start sphere tracking, mark off a location, then select an item.
The item will now be bound to that location, and the tracker will
take that item placement into account for sphere
calculations. The item's icon (at the time that you marked it off)
will now appear next to the check in the location list.
Unmarking the location will also unbind the item that was tracked there.
When you mouse over an item in the inventory section, a tooltip will
appear with all the locations you tracked that item to appear in.
""",
)
12 changes: 12 additions & 0 deletions gui/ui/main.ui
Original file line number Diff line number Diff line change
Expand Up @@ -3820,6 +3820,13 @@ QPushButton {
</property>
</widget>
</item>
<item>
<widget class="TrackerToggleSTButton" name="toggle_sphere_tracking_button">
<property name="text">
<string>Enable Sphere Tracking</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="tracker_sphere_tracking_label">
<property name="text">
Expand Down Expand Up @@ -4126,6 +4133,11 @@ QPushButton {
<extends>QCheckBox</extends>
<header>gui/components/tristate_check_box</header>
</customwidget>
<customwidget>
<class>TrackerToggleSTButton</class>
<extends>QPushButton</extends>
<header>gui/components/tracker_toggle_st_button</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
Expand Down
7 changes: 7 additions & 0 deletions gui/ui/ui_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
QSizePolicy, QSpacerItem, QSpinBox, QTabWidget,
QVBoxLayout, QWidget)

from gui.components.tracker_toggle_st_button import TrackerToggleSTButton
from gui.components.tristate_check_box import RandoTriStateCheckBox

class Ui_main_window(object):
Expand Down Expand Up @@ -2551,6 +2552,11 @@ def setupUi(self, main_window):

self.tracker_info_layout.addWidget(self.set_hints_button)

self.toggle_sphere_tracking_button = TrackerToggleSTButton(self.tracker_tab)
self.toggle_sphere_tracking_button.setObjectName(u"toggle_sphere_tracking_button")

self.tracker_info_layout.addWidget(self.toggle_sphere_tracking_button)

self.tracker_sphere_tracking_label = QLabel(self.tracker_tab)
self.tracker_sphere_tracking_label.setObjectName(u"tracker_sphere_tracking_label")

Expand Down Expand Up @@ -3031,6 +3037,7 @@ def retranslateUi(self, main_window):
self.check_all_in_logic_button.setText(QCoreApplication.translate("main_window", u"Check All in Logic", None))
self.uncheck_all_button.setText(QCoreApplication.translate("main_window", u"Uncheck All", None))
self.set_hints_button.setText(QCoreApplication.translate("main_window", u"Set Hints", None))
self.toggle_sphere_tracking_button.setText(QCoreApplication.translate("main_window", u"Enable Sphere Tracking", None))
self.tracker_sphere_tracking_label.setText(QCoreApplication.translate("main_window", u"Sphere Tracking", None))
self.cancel_sphere_tracking_button.setText(QCoreApplication.translate("main_window", u"Cancel Sphere Tracking for Location", None))
self.tab_widget.setTabText(self.tab_widget.indexOf(self.tracker_tab), QCoreApplication.translate("main_window", u"Tracker", None))
Expand Down

0 comments on commit d1cc067

Please sign in to comment.