Skip to content

Commit

Permalink
Merge branch 'Gugubo-gem-tracker' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
gmjosack committed Nov 28, 2023
2 parents 0537e35 + 9f39429 commit 1841603
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/modlunky2/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,24 @@ class TimerTrackerConfig(CommonTrackerConfig):
show_ils: bool = field(default=False, skip_if_default=True)


@serialize(rename_all="kebabcase")
@deserialize(rename_all="kebabcase")
@dataclass
class GemTrackerConfig(CommonTrackerConfig):
show_total_gem_count: bool = field(default=True, skip_if_default=True)
show_colored_gem_count: bool = field(default=True, skip_if_default=True)
show_diamond_count: bool = field(default=True, skip_if_default=True)
show_diamond_percentage: bool = field(default=True, skip_if_default=True)


@serialize(rename_all="kebabcase")
@deserialize(rename_all="kebabcase")
@dataclass
class TrackersConfig:
category: CategoryTrackerConfig = field(default_factory=CategoryTrackerConfig)
pacifist: PacifistTrackerConfig = field(default_factory=PacifistTrackerConfig)
timer: TimerTrackerConfig = field(default_factory=TimerTrackerConfig)
gem: GemTrackerConfig = field(default_factory=GemTrackerConfig)


@serialize # Note: these fields aren't renamed for historical reasons
Expand Down
12 changes: 12 additions & 0 deletions src/modlunky2/mem/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
poly_pointer,
struct_field,
dc_struct,
array,
pointer,
sc_uint8,
sc_uint32,
Expand Down Expand Up @@ -119,6 +120,14 @@ def _make_entity_type_enum():
EntityType.ITEM_POWERUP_TRUECROWN,
}

GEMS = {
EntityType.ITEM_RUBY,
EntityType.ITEM_EMERALD,
EntityType.ITEM_SAPPHIRE,
EntityType.ITEM_DIAMOND,
}
DIAMOND = EntityType.ITEM_DIAMOND


class Layer(IntEnum):
FRONT = 0
Expand Down Expand Up @@ -210,6 +219,9 @@ class Inventory:
ropes: int = struct_field(0x05, sc_uint8, default=4)
poison_tick_timer: int = struct_field(0x06, sc_int16, default=-1)
cursed: bool = struct_field(0x08, sc_bool, default=False)
collected_money: Tuple[EntityType, ...] = struct_field(
0x20, array(sc_uint32, 512), default=tuple()
)
kills_level: int = struct_field(0x1424, sc_uint32, default=0)
kills_total: int = struct_field(0x1428, sc_uint32, default=0)
collected_money_total: int = struct_field(0x1520, sc_uint32, default=0)
Expand Down
Binary file added src/modlunky2/static/images/gem.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/modlunky2/ui/trackers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .options import OptionsFrame
from .pacifist import PacifistButtons
from .timer import TimerButtons
from .gem import GemButtons

logger = logging.getLogger(__name__)

Expand All @@ -23,6 +24,7 @@ def __init__(self, parent, ml_config: Config, *args, **kwargs):
self.add_button(PacifistButtons(self, self.ml_config))
self.add_button(CategoryButtons(self, self.ml_config))
self.add_button(TimerButtons(self, self.ml_config))
self.add_button(GemButtons(self, self.ml_config))

self.rowconfigure(self.button_index, weight=1)

Expand Down
239 changes: 239 additions & 0 deletions src/modlunky2/ui/trackers/gem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
import logging
import tkinter as tk
from tkinter import ttk

from PIL import Image, ImageTk

from modlunky2.config import Config, GemTrackerConfig
from modlunky2.constants import BASE_DIR
from modlunky2.mem import Spel2Process

from modlunky2.mem.entities import GEMS, DIAMOND

from modlunky2.ui.trackers.common import (
Tracker,
TrackerWindow,
WindowData,
)

logger = logging.getLogger(__name__)


ICON_PATH = BASE_DIR / "static/images"


class GemModifiers(ttk.LabelFrame):
def __init__(self, parent, gem_tracker_config: GemTrackerConfig, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.parent = parent

self.gem_tracker_config = gem_tracker_config

self.show_total_gem_count = tk.BooleanVar()
self.show_total_gem_count.set(self.gem_tracker_config.show_total_gem_count)
self.show_gem_count_checkbox = ttk.Checkbutton(
self,
text="Total Gem Count",
variable=self.show_total_gem_count,
onvalue=True,
offvalue=False,
command=self.toggle_show_total_gem_count,
)
self.show_gem_count_checkbox.grid(row=0, column=1, pady=5, padx=5, sticky="w")

self.show_colored_gem_count = tk.BooleanVar()
self.show_colored_gem_count.set(self.gem_tracker_config.show_colored_gem_count)
self.show_colored_gem_count_checkbox = ttk.Checkbutton(
self,
text="Colored Gem Count",
variable=self.show_colored_gem_count,
onvalue=True,
offvalue=False,
command=self.toggle_show_colored_gem_count,
)
self.show_colored_gem_count_checkbox.grid(
row=0, column=2, pady=5, padx=5, sticky="w"
)

self.show_diamond_count = tk.BooleanVar()
self.show_diamond_count.set(self.gem_tracker_config.show_diamond_count)
self.show_diamond_count_checkbox = ttk.Checkbutton(
self,
text="Diamond Count",
variable=self.show_diamond_count,
onvalue=True,
offvalue=False,
command=self.toggle_show_diamond_count,
)
self.show_diamond_count_checkbox.grid(
row=0, column=3, pady=5, padx=5, sticky="w"
)

self.show_diamond_percentage = tk.BooleanVar()
self.show_diamond_percentage.set(
self.gem_tracker_config.show_diamond_percentage
)
self.show_diamond_percentage_checkbox = ttk.Checkbutton(
self,
text="Diamond Percentage",
variable=self.show_diamond_percentage,
onvalue=True,
offvalue=False,
command=self.toggle_show_diamond_percentage,
)
self.show_diamond_percentage_checkbox.grid(
row=0, column=4, pady=5, padx=5, sticky="w"
)

def toggle_show_total_gem_count(self):
self.gem_tracker_config.show_total_gem_count = self.show_total_gem_count.get()
self.parent.config_update_callback()

def toggle_show_colored_gem_count(self):
self.gem_tracker_config.show_colored_gem_count = (
self.show_colored_gem_count.get()
)
self.parent.config_update_callback()

def toggle_show_diamond_count(self):
self.gem_tracker_config.show_diamond_count = self.show_diamond_count.get()
self.parent.config_update_callback()

def toggle_show_diamond_percentage(self):
self.gem_tracker_config.show_diamond_percentage = (
self.show_diamond_percentage.get()
)
self.parent.config_update_callback()


class GemButtons(ttk.Frame):
def __init__(self, parent, modlunky_config: Config, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.modlunky_config = modlunky_config
self.columnconfigure(0, weight=1, minsize=200)
self.columnconfigure(1, weight=10000)
self.rowconfigure(0, minsize=60)
self.window = None

self.gem_icon = ImageTk.PhotoImage(
Image.open(ICON_PATH / "gem.png").resize((24, 24), Image.Resampling.LANCZOS)
)

self.gem_button = ttk.Button(
self,
text="Gem",
image=self.gem_icon,
compound="left",
command=self.launch,
width=1,
)
self.gem_button.grid(row=0, column=0, pady=5, padx=5, sticky="nswe")

self.modifiers = GemModifiers(
self, self.modlunky_config.trackers.gem, text="Gem Tracker Options"
)
self.modifiers.grid(row=0, column=1, pady=5, padx=5, sticky="nswe")

def launch(self):
self.disable_button()
self.window = TrackerWindow(
title="Gem Tracker",
color_key=self.modlunky_config.tracker_color_key,
font_size=self.modlunky_config.tracker_font_size,
font_family=self.modlunky_config.tracker_font_family,
on_close=self.window_closed,
file_name="gem.txt",
tracker=GemTracker(),
config=self.modlunky_config.trackers.gem,
)

def config_update_callback(self):
self.modlunky_config.save()
if self.window:
self.window.update_config(self.modlunky_config.trackers.gem)

def window_closed(self):
self.window = None
# If we're in the midst of destroy() the button might not exist
if self.gem_button.winfo_exists():
self.gem_button["state"] = tk.NORMAL

def disable_button(self):
self.gem_button["state"] = tk.DISABLED


class GemTracker(Tracker[GemTrackerConfig, WindowData]):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.gems_total = 0
self.gems_level = 0
self.diamonds_total = 0
self.diamonds_level = 0

self.world = 0
self.level = 0

def initialize(self):
self.gems_total = 0
self.gems_level = 0
self.diamonds_total = 0
self.diamonds_level = 0

self.world = 0
self.level = 0

def poll(self, proc: Spel2Process, config: GemTrackerConfig) -> WindowData:
game_state = proc.get_state()
if game_state is None:
return None

world = game_state.world
level = game_state.level

# Save gems on level change
if world != self.world or level != self.level:
self.world = world
self.level = level
self.gems_total += self.gems_level
self.diamonds_total += self.diamonds_level

# Reset gem count on restart
if world == game_state.world_start and level == game_state.level_start:
self.gems_total = 0
self.diamonds_total = 0

# Count gems in current level
if game_state.items is not None:
player = game_state.items.players[0]
if player is not None and player.inventory is not None:
gems = 0
diamonds = 0

collected_money = player.inventory.collected_money
for entity in collected_money:
if entity in GEMS:
gems += 1
if entity == DIAMOND:
diamonds += 1

self.gems_level = gems
self.diamonds_level = diamonds

label = self.get_text(config)
return WindowData(label)

def get_text(self, config: GemTrackerConfig):
gems = self.gems_total + self.gems_level
diamonds = self.diamonds_total + self.diamonds_level
out = []
if config.show_total_gem_count:
out.append(f"{'Total gems': >13}: {gems : <4}")
if config.show_colored_gem_count:
out.append(f"{'Colorful gems': >13}: {gems-diamonds: <4}")
if config.show_diamond_count:
out.append(f"{'Diamonds': >13}: {diamonds: <4}")
if config.show_diamond_percentage:
diamond_rate = str(round(diamonds / gems * 100) if gems > 0 else 0) + "%"
out.append(f"{'Diamond rate': >13}: {diamond_rate: <4}")

return "\n".join(out)

0 comments on commit 1841603

Please sign in to comment.