DevourUnlocker/standalone/gui.py
MiTHRAL 4af18a2f75
Some checks are pending
Build DevourUnlocker / windows-cross (push) Waiting to run
Build DevourUnlocker / linux (push) Waiting to run
Build DevourUnlocker / standalone (push) Waiting to run
v2.0.1: expand to all item types + fix pets + linux CI
- Config: add allPets (Crow/Pig/Goat/Rat/Spider/Cat/Pug), allPerks (29 inc Acceleration/Quartermaster etc), flashlights/emotes/outfits; unlockOutfits global
- Resolver: resolve HasPerk/HasPet/UpdateLocked* for Pets/Perks/Flashlights/Emotes/Outfits/Robes
- Patches: hook IsRobe/IsCharacter + HasPerk/HasOutfit + UpdateLockedPets/Perks/Flashlights/Emotes/Outfits/Robes bypass — fixes pets not unlocking
- GUI: 7 tabs (Robes/Chars/Perks/Pets/Flashlights/Emotes/Outfits), Unlock All covers all categories
- Standalone: --perks/--pets/--all now covers all categories, petOverrides etc, list shows 30 robes+9 chars+29 perks+7 pets+8 flashlights+12 emotes+8 outfits
- GUI standalone: 7 notebooks with per-category checkboxes
- BepInEx: add UpdateLocked* prefix patches + HasPerk/HasOutfit, GUI tabs for all
- CI: switch windows-latest to ubuntu-latest mingw cross (git.mithraic.cloud has only linux runner, windows jobs were stuck Waiting)
2026-08-21 21:15:58 -04:00

71 lines
3.9 KiB
Python
Executable file

#!/usr/bin/env python3
"""Tkinter GUI for standalone — selective checkboxes, writes DevourUnlocker.json"""
import tkinter as tk
from tkinter import ttk, messagebox
import json, pathlib
from devour_unlocker import ROBES, CHARS, PERKS, PETS, FLASHLIGHTS, EMOTES, OUTFITS, default_json_path, load_config, save_config
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("DevourUnlocker — Selective Unlock")
self.geometry("560x680")
self.json_path = default_json_path()
self.cfg = load_config(str(self.json_path))
self.vars = {}
self._build()
def _build(self):
ttk.Label(self, text="DevourUnlocker v2 — Standalone (multiplayer safe)").pack(pady=6)
ttk.Label(self, text=f"Config: {self.json_path}").pack()
btn_row = ttk.Frame(self); btn_row.pack(pady=6)
ttk.Button(btn_row, text="Unlock All", command=self.unlock_all).pack(side=tk.LEFT, padx=4)
ttk.Button(btn_row, text="Lock All", command=self.lock_all).pack(side=tk.LEFT, padx=4)
ttk.Button(btn_row, text="Save", command=self.save).pack(side=tk.LEFT, padx=4)
ttk.Button(btn_row, text="Reload", command=self.reload).pack(side=tk.LEFT, padx=4)
nb = ttk.Notebook(self); nb.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)
for title, items in [("Robes", ROBES), ("Characters", CHARS), ("Perks", PERKS), ("Pets", PETS), ("Flashlights", FLASHLIGHTS), ("Emotes", EMOTES), ("Outfits", OUTFITS)]:
f = ttk.Frame(nb)
nb.add(f, text=title)
canvas = tk.Canvas(f)
scroll = ttk.Scrollbar(f, command=canvas.yview)
inner = ttk.Frame(canvas)
inner.bind("<Configure>", lambda e, c=canvas: c.configure(scrollregion=c.bbox("all")))
canvas.create_window((0,0), window=inner, anchor="nw")
canvas.configure(yscrollcommand=scroll.set)
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scroll.pack(side=tk.RIGHT, fill=tk.Y)
for name in items:
key_map={"Robes":("robeOverrides","unlockRobes"),"Characters":("characterOverrides","unlockCharacters"),"Perks":("perkOverrides","unlockPerks"),"Pets":("petOverrides","unlockPets"),"Flashlights":("flashlightOverrides","unlockFlashlights"),"Emotes":("emoteOverrides","unlockEmotes"),"Outfits":("outfitOverrides","unlockOutfits")}
k, g = key_map[title]
cur = self.cfg.get(k, {}).get(name, self.cfg.get(g, True))
var = tk.BooleanVar(value=bool(cur))
self.vars[(title,name)] = var
ttk.Checkbutton(inner, text=name, variable=var).pack(anchor="w", padx=8, pady=2)
def unlock_all(self):
for v in self.vars.values(): v.set(True)
def lock_all(self):
for v in self.vars.values(): v.set(False)
def reload(self):
self.cfg = load_config(str(self.json_path))
self.destroy(); self.__init__()
def save(self):
def compress(title, items, k, g):
over = {n: self.vars[(title,n)].get() for n in items}
if all(over.values()): self.cfg[g]=True; self.cfg.pop(k,None)
elif not any(over.values()): self.cfg[g]=False; self.cfg.pop(k,None)
else: self.cfg[k]=over; self.cfg[g]=True
compress("Robes", ROBES, "robeOverrides", "unlockRobes")
compress("Characters", CHARS, "characterOverrides", "unlockCharacters")
compress("Perks", PERKS, "perkOverrides", "unlockPerks")
compress("Pets", PETS, "petOverrides", "unlockPets")
compress("Flashlights", FLASHLIGHTS, "flashlightOverrides", "unlockFlashlights")
compress("Emotes", EMOTES, "emoteOverrides", "unlockEmotes")
compress("Outfits", OUTFITS, "outfitOverrides", "unlockOutfits")
save_config(str(self.json_path), self.cfg)
messagebox.showinfo("Saved", f"Wrote {self.json_path}\nLaunch Devour with winhttp.dll enabled.")
if __name__ == "__main__":
App().mainloop()