- 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)
71 lines
3.9 KiB
Python
Executable file
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()
|