Sort Game Options
Placate Adjuster in the interim
This commit is contained in:
161
Gui.py
161
Gui.py
@@ -17,6 +17,7 @@ from gui.randomize.entrando import entrando_page
|
||||
from gui.randomize.enemizer import enemizer_page
|
||||
from gui.randomize.dungeon import dungeon_page
|
||||
from gui.randomize.multiworld import multiworld_page
|
||||
from gui.randomize.gameoptions import gameoptions_page
|
||||
from GuiUtils import ToolTips, set_icon, BackgroundTaskProgress
|
||||
from Main import main, __version__ as ESVersion
|
||||
from Rom import Sprite
|
||||
@@ -94,7 +95,7 @@ def guiMain(args=None):
|
||||
randomizerNotebook.add(multiworldWindow, text="Multiworld")
|
||||
|
||||
# Game Options
|
||||
gameOptionsWindow = ttk.Frame(randomizerNotebook)
|
||||
gameOptionsWindow = gameoptions_page(randomizerNotebook)
|
||||
randomizerNotebook.add(gameOptionsWindow, text="Game Options")
|
||||
|
||||
# Generation Setup
|
||||
@@ -112,15 +113,11 @@ def guiMain(args=None):
|
||||
createSpoilerCheckbutton = Checkbutton(checkBoxFrame, text="Create Spoiler Log", variable=createSpoilerVar)
|
||||
suppressRomVar = IntVar()
|
||||
suppressRomCheckbutton = Checkbutton(checkBoxFrame, text="Do not create patched Rom", variable=suppressRomVar)
|
||||
hintsVar = IntVar()
|
||||
hintsVar.set(1) #set default
|
||||
hintsCheckbutton = Checkbutton(checkBoxFrame, text="Include Helpful Hints", variable=hintsVar)
|
||||
customVar = IntVar()
|
||||
customCheckbutton = Checkbutton(checkBoxFrame, text="Use custom item pool", variable=customVar)
|
||||
|
||||
createSpoilerCheckbutton.pack(expand=True, anchor=W)
|
||||
suppressRomCheckbutton.pack(expand=True, anchor=W)
|
||||
hintsCheckbutton.pack(expand=True, anchor=W)
|
||||
customCheckbutton.pack(expand=True, anchor=W)
|
||||
|
||||
romOptionsFrame = LabelFrame(rightHalfFrame, text="Rom options")
|
||||
@@ -129,87 +126,6 @@ def guiMain(args=None):
|
||||
for i in range(5):
|
||||
romOptionsFrame.rowconfigure(i, weight=1)
|
||||
|
||||
disableMusicVar = IntVar()
|
||||
disableMusicCheckbutton = Checkbutton(romOptionsFrame, text="Disable music", variable=disableMusicVar)
|
||||
disableMusicCheckbutton.grid(row=0, column=0, sticky=E)
|
||||
|
||||
spriteDialogFrame = Frame(romOptionsFrame)
|
||||
spriteDialogFrame.grid(row=0, column=1)
|
||||
baseSpriteLabel = Label(spriteDialogFrame, text='Sprite:')
|
||||
|
||||
spriteNameVar = StringVar()
|
||||
sprite = None
|
||||
def set_sprite(sprite_param):
|
||||
nonlocal sprite
|
||||
if sprite_param is None or not sprite_param.valid:
|
||||
sprite = None
|
||||
spriteNameVar.set('(unchanged)')
|
||||
else:
|
||||
sprite = sprite_param
|
||||
spriteNameVar.set(sprite.name)
|
||||
|
||||
set_sprite(None)
|
||||
spriteNameVar.set('(unchanged)')
|
||||
spriteEntry = Label(spriteDialogFrame, textvariable=spriteNameVar)
|
||||
|
||||
def SpriteSelect():
|
||||
SpriteSelector(mainWindow, set_sprite)
|
||||
|
||||
spriteSelectButton = Button(spriteDialogFrame, text='...', command=SpriteSelect)
|
||||
|
||||
baseSpriteLabel.pack(side=LEFT)
|
||||
spriteEntry.pack(side=LEFT)
|
||||
spriteSelectButton.pack(side=LEFT)
|
||||
|
||||
quickSwapVar = IntVar()
|
||||
quickSwapCheckbutton = Checkbutton(romOptionsFrame, text="L/R Quickswapping", variable=quickSwapVar)
|
||||
quickSwapCheckbutton.grid(row=1, column=0, sticky=E)
|
||||
|
||||
fastMenuFrame = Frame(romOptionsFrame)
|
||||
fastMenuFrame.grid(row=1, column=1, sticky=E)
|
||||
fastMenuLabel = Label(fastMenuFrame, text='Menu speed')
|
||||
fastMenuLabel.pack(side=LEFT)
|
||||
fastMenuVar = StringVar()
|
||||
fastMenuVar.set('normal')
|
||||
fastMenuOptionMenu = OptionMenu(fastMenuFrame, fastMenuVar, 'normal', 'instant', 'double', 'triple', 'quadruple', 'half')
|
||||
fastMenuOptionMenu.pack(side=LEFT)
|
||||
|
||||
heartcolorFrame = Frame(romOptionsFrame)
|
||||
heartcolorFrame.grid(row=2, column=0, sticky=E)
|
||||
heartcolorLabel = Label(heartcolorFrame, text='Heart color')
|
||||
heartcolorLabel.pack(side=LEFT)
|
||||
heartcolorVar = StringVar()
|
||||
heartcolorVar.set('red')
|
||||
heartcolorOptionMenu = OptionMenu(heartcolorFrame, heartcolorVar, 'red', 'blue', 'green', 'yellow', 'random')
|
||||
heartcolorOptionMenu.pack(side=LEFT)
|
||||
|
||||
heartbeepFrame = Frame(romOptionsFrame)
|
||||
heartbeepFrame.grid(row=2, column=1, sticky=E)
|
||||
heartbeepLabel = Label(heartbeepFrame, text='Heartbeep')
|
||||
heartbeepLabel.pack(side=LEFT)
|
||||
heartbeepVar = StringVar()
|
||||
heartbeepVar.set('normal')
|
||||
heartbeepOptionMenu = OptionMenu(heartbeepFrame, heartbeepVar, 'double', 'normal', 'half', 'quarter', 'off')
|
||||
heartbeepOptionMenu.pack(side=LEFT)
|
||||
|
||||
owPalettesFrame = Frame(romOptionsFrame)
|
||||
owPalettesFrame.grid(row=3, column=0, sticky=E)
|
||||
owPalettesLabel = Label(owPalettesFrame, text='Overworld palettes')
|
||||
owPalettesLabel.pack(side=LEFT)
|
||||
owPalettesVar = StringVar()
|
||||
owPalettesVar.set('default')
|
||||
owPalettesOptionMenu = OptionMenu(owPalettesFrame, owPalettesVar, 'default', 'random', 'blackout')
|
||||
owPalettesOptionMenu.pack(side=LEFT)
|
||||
|
||||
uwPalettesFrame = Frame(romOptionsFrame)
|
||||
uwPalettesFrame.grid(row=3, column=1, sticky=E)
|
||||
uwPalettesLabel = Label(uwPalettesFrame, text='Dungeon palettes')
|
||||
uwPalettesLabel.pack(side=LEFT)
|
||||
uwPalettesVar = StringVar()
|
||||
uwPalettesVar.set('default')
|
||||
uwPalettesOptionMenu = OptionMenu(uwPalettesFrame, uwPalettesVar, 'default', 'random', 'blackout')
|
||||
uwPalettesOptionMenu.pack(side=LEFT)
|
||||
|
||||
romDialogFrame = Frame(romOptionsFrame)
|
||||
romDialogFrame.grid(row=4, column=0, columnspan=2, sticky=W+E)
|
||||
|
||||
@@ -269,9 +185,9 @@ def guiMain(args=None):
|
||||
guiargs.algorithm = itemWindow.algorithmVar.get()
|
||||
guiargs.shuffle = entrandoWindow.shuffleVar.get()
|
||||
guiargs.door_shuffle = doorShuffleVar.get()
|
||||
guiargs.heartbeep = heartbeepVar.get()
|
||||
guiargs.heartcolor = heartcolorVar.get()
|
||||
guiargs.fastmenu = fastMenuVar.get()
|
||||
guiargs.heartbeep = gameOptionsWindow.heartbeepVar.get()
|
||||
guiargs.heartcolor = gameOptionsWindow.heartcolorVar.get()
|
||||
guiargs.fastmenu = gameOptionsWindow.fastMenuVar.get()
|
||||
guiargs.create_spoiler = bool(createSpoilerVar.get())
|
||||
guiargs.skip_playthrough = not bool(createSpoilerVar.get())
|
||||
guiargs.suppress_rom = bool(suppressRomVar.get())
|
||||
@@ -281,12 +197,12 @@ def guiMain(args=None):
|
||||
guiargs.keyshuffle = bool(dungeonRandoWindow.keyshuffleVar.get())
|
||||
guiargs.bigkeyshuffle = bool(dungeonRandoWindow.bigkeyshuffleVar.get())
|
||||
guiargs.retro = bool(itemWindow.retroVar.get())
|
||||
guiargs.quickswap = bool(quickSwapVar.get())
|
||||
guiargs.disablemusic = bool(disableMusicVar.get())
|
||||
guiargs.ow_palettes = owPalettesVar.get()
|
||||
guiargs.uw_palettes = uwPalettesVar.get()
|
||||
guiargs.quickswap = bool(gameOptionsWindow.quickSwapVar.get())
|
||||
guiargs.disablemusic = bool(gameOptionsWindow.disableMusicVar.get())
|
||||
guiargs.ow_palettes = gameOptionsWindow.owPalettesVar.get()
|
||||
guiargs.uw_palettes = gameOptionsWindow.uwPalettesVar.get()
|
||||
guiargs.shuffleganon = bool(entrandoWindow.shuffleGanonVar.get())
|
||||
guiargs.hints = bool(hintsVar.get())
|
||||
guiargs.hints = bool(gameOptionsWindow.hintsVar.get())
|
||||
guiargs.enemizercli = enemizerWindow.enemizerCLIpathVar.get()
|
||||
guiargs.shufflebosses = enemizerWindow.enemizerBossVar.get()
|
||||
guiargs.shuffleenemies = enemizerWindow.enemyShuffleVar.get()
|
||||
@@ -304,7 +220,7 @@ def guiMain(args=None):
|
||||
int(rupee300Var.get()), int(rupoorVar.get()), int(blueclockVar.get()), int(greenclockVar.get()), int(redclockVar.get()), int(progbowVar.get()), int(bomb10Var.get()), int(triforcepieceVar.get()),
|
||||
int(triforcecountVar.get()), int(triforceVar.get()), int(rupoorcostVar.get()), int(universalkeyVar.get())]
|
||||
guiargs.rom = romVar.get()
|
||||
guiargs.sprite = sprite
|
||||
# guiargs.sprite = gameOptionsWindow.sprite
|
||||
guiargs.outputpath = args.outputpath if args else None
|
||||
# get default values for missing parameters
|
||||
for k,v in vars(parse_arguments(['--multi', str(guiargs.multi)])).items():
|
||||
@@ -347,8 +263,8 @@ def guiMain(args=None):
|
||||
rightHalfFrame2 = Frame(topFrame2)
|
||||
checkBoxFrame2 = Frame(rightHalfFrame2)
|
||||
|
||||
quickSwapCheckbutton2 = Checkbutton(checkBoxFrame2, text="Enabled L/R Item quickswapping", variable=quickSwapVar)
|
||||
disableMusicCheckbutton2 = Checkbutton(checkBoxFrame2, text="Disable game music", variable=disableMusicVar)
|
||||
quickSwapCheckbutton2 = Checkbutton(checkBoxFrame2, text="Enabled L/R Item quickswapping", variable=gameOptionsWindow.quickSwapVar)
|
||||
disableMusicCheckbutton2 = Checkbutton(checkBoxFrame2, text="Disable game music", variable=gameOptionsWindow.disableMusicVar)
|
||||
|
||||
quickSwapCheckbutton2.pack(expand=True, anchor=W)
|
||||
disableMusicCheckbutton2.pack(expand=True, anchor=W)
|
||||
@@ -371,10 +287,11 @@ def guiMain(args=None):
|
||||
|
||||
spriteDialogFrame2 = Frame(fileDialogFrame2)
|
||||
baseSpriteLabel2 = Label(spriteDialogFrame2, text='Link Sprite')
|
||||
spriteEntry2 = Label(spriteDialogFrame2, textvariable=spriteNameVar)
|
||||
spriteEntry2 = Label(spriteDialogFrame2, textvariable=gameOptionsWindow.spriteNameVar)
|
||||
|
||||
def SpriteSelectAdjuster():
|
||||
SpriteSelector(mainWindow, set_sprite, adjuster=True)
|
||||
pass
|
||||
# SpriteSelector(mainWindow, gameOptionsWindow.set_sprite, adjuster=True)
|
||||
|
||||
spriteSelectButton2 = Button(spriteDialogFrame2, text='Select Sprite', command=SpriteSelectAdjuster)
|
||||
|
||||
@@ -390,31 +307,31 @@ def guiMain(args=None):
|
||||
|
||||
drowDownFrame2 = Frame(topFrame2)
|
||||
heartbeepFrame2 = Frame(drowDownFrame2)
|
||||
heartbeepOptionMenu2 = OptionMenu(heartbeepFrame2, heartbeepVar, 'double', 'normal', 'half', 'quarter', 'off')
|
||||
heartbeepOptionMenu2 = OptionMenu(heartbeepFrame2, gameOptionsWindow.heartbeepVar, 'double', 'normal', 'half', 'quarter', 'off')
|
||||
heartbeepOptionMenu2.pack(side=RIGHT)
|
||||
heartbeepLabel2 = Label(heartbeepFrame2, text='Heartbeep sound rate')
|
||||
heartbeepLabel2.pack(side=LEFT)
|
||||
|
||||
heartcolorFrame2 = Frame(drowDownFrame2)
|
||||
heartcolorOptionMenu2 = OptionMenu(heartcolorFrame2, heartcolorVar, 'red', 'blue', 'green', 'yellow', 'random')
|
||||
heartcolorOptionMenu2 = OptionMenu(heartcolorFrame2, gameOptionsWindow.heartcolorVar, 'red', 'blue', 'green', 'yellow', 'random')
|
||||
heartcolorOptionMenu2.pack(side=RIGHT)
|
||||
heartcolorLabel2 = Label(heartcolorFrame2, text='Heart color')
|
||||
heartcolorLabel2.pack(side=LEFT)
|
||||
|
||||
fastMenuFrame2 = Frame(drowDownFrame2)
|
||||
fastMenuOptionMenu2 = OptionMenu(fastMenuFrame2, fastMenuVar, 'normal', 'instant', 'double', 'triple', 'quadruple', 'half')
|
||||
fastMenuOptionMenu2 = OptionMenu(fastMenuFrame2, gameOptionsWindow.fastMenuVar, 'normal', 'instant', 'double', 'triple', 'quadruple', 'half')
|
||||
fastMenuOptionMenu2.pack(side=RIGHT)
|
||||
fastMenuLabel2 = Label(fastMenuFrame2, text='Menu speed')
|
||||
fastMenuLabel2.pack(side=LEFT)
|
||||
|
||||
owPalettesFrame2 = Frame(drowDownFrame2)
|
||||
owPalettesOptionMenu2 = OptionMenu(owPalettesFrame2, owPalettesVar, 'default', 'random', 'blackout')
|
||||
owPalettesOptionMenu2 = OptionMenu(owPalettesFrame2, gameOptionsWindow.owPalettesVar, 'default', 'random', 'blackout')
|
||||
owPalettesOptionMenu2.pack(side=RIGHT)
|
||||
owPalettesLabel2 = Label(owPalettesFrame2, text='Overworld palettes')
|
||||
owPalettesLabel2.pack(side=LEFT)
|
||||
|
||||
uwPalettesFrame2 = Frame(drowDownFrame2)
|
||||
uwPalettesOptionMenu2 = OptionMenu(uwPalettesFrame2, uwPalettesVar, 'default', 'random', 'blackout')
|
||||
uwPalettesOptionMenu2 = OptionMenu(uwPalettesFrame2, gameOptionsWindow.uwPalettesVar, 'default', 'random', 'blackout')
|
||||
uwPalettesOptionMenu2.pack(side=RIGHT)
|
||||
uwPalettesLabel2 = Label(uwPalettesFrame2, text='Dungeon palettes')
|
||||
uwPalettesLabel2.pack(side=LEFT)
|
||||
@@ -429,16 +346,16 @@ def guiMain(args=None):
|
||||
|
||||
def adjustRom():
|
||||
guiargs = Namespace()
|
||||
guiargs.heartbeep = heartbeepVar.get()
|
||||
guiargs.heartcolor = heartcolorVar.get()
|
||||
guiargs.fastmenu = fastMenuVar.get()
|
||||
guiargs.ow_palettes = owPalettesVar.get()
|
||||
guiargs.uw_palettes = uwPalettesVar.get()
|
||||
guiargs.quickswap = bool(quickSwapVar.get())
|
||||
guiargs.disablemusic = bool(disableMusicVar.get())
|
||||
guiargs.heartbeep = gameOptionsWindow.heartbeepVar.get()
|
||||
guiargs.heartcolor = gameOptionsWindow.heartcolorVar.get()
|
||||
guiargs.fastmenu = gameOptionsWindow.fastMenuVar.get()
|
||||
guiargs.ow_palettes = gameOptionsWindow.owPalettesVar.get()
|
||||
guiargs.uw_palettes = gameOptionsWindow.uwPalettesVar.get()
|
||||
guiargs.quickswap = bool(gameOptionsWindow.quickSwapVar.get())
|
||||
guiargs.disablemusic = bool(gameOptionsWindow.disableMusicVar.get())
|
||||
guiargs.rom = romVar2.get()
|
||||
guiargs.baserom = romVar.get()
|
||||
guiargs.sprite = sprite
|
||||
# guiargs.sprite = sprite
|
||||
try:
|
||||
adjust(args=guiargs)
|
||||
except Exception as e:
|
||||
@@ -1061,8 +978,8 @@ def guiMain(args=None):
|
||||
dungeonRandoWindow.bigkeyshuffleVar.set(args.bigkeyshuffle)
|
||||
itemWindow.retroVar.set(args.retro)
|
||||
entrandoWindow.openpyramidVar.set(args.openpyramid)
|
||||
quickSwapVar.set(int(args.quickswap))
|
||||
disableMusicVar.set(int(args.disablemusic))
|
||||
gameOptionsWindow.quickSwapVar.set(int(args.quickswap))
|
||||
gameOptionsWindow.disableMusicVar.set(int(args.disablemusic))
|
||||
if args.multi:
|
||||
multiworldWindow.worldVar.set(str(args.multi))
|
||||
if args.count:
|
||||
@@ -1082,23 +999,23 @@ def guiMain(args=None):
|
||||
itemWindow.algorithmVar.set(args.algorithm)
|
||||
entrandoWindow.shuffleVar.set(args.shuffle)
|
||||
doorShuffleVar.set(args.door_shuffle)
|
||||
heartcolorVar.set(args.heartcolor)
|
||||
heartbeepVar.set(args.heartbeep)
|
||||
fastMenuVar.set(args.fastmenu)
|
||||
gameOptionsWindow.heartcolorVar.set(args.heartcolor)
|
||||
gameOptionsWindow.heartbeepVar.set(args.heartbeep)
|
||||
gameOptionsWindow.fastMenuVar.set(args.fastmenu)
|
||||
itemWindow.logicVar.set(args.logic)
|
||||
romVar.set(args.rom)
|
||||
entrandoWindow.shuffleGanonVar.set(args.shuffleganon)
|
||||
hintsVar.set(args.hints)
|
||||
gameOptionsWindow.hintsVar.set(args.hints)
|
||||
enemizerWindow.enemizerCLIpathVar.set(args.enemizercli)
|
||||
enemizerWindow.potShuffleVar.set(args.shufflepots)
|
||||
enemizerWindow.enemyShuffleVar.set(args.shuffleenemies)
|
||||
enemizerWindow.enemizerBossVar.set(args.shufflebosses)
|
||||
enemizerWindow.enemizerDamageVar.set(args.enemy_damage)
|
||||
enemizerWindow.enemizerHealthVar.set(args.enemy_health)
|
||||
owPalettesVar.set(args.ow_palettes)
|
||||
uwPalettesVar.set(args.uw_palettes)
|
||||
if args.sprite is not None:
|
||||
set_sprite(Sprite(args.sprite))
|
||||
gameOptionsWindow.owPalettesVar.set(args.ow_palettes)
|
||||
gameOptionsWindow.uwPalettesVar.set(args.uw_palettes)
|
||||
# if args.sprite is not None:
|
||||
# gameOptionsWindow.set_sprite(Sprite(args.sprite))
|
||||
|
||||
mainWindow.mainloop()
|
||||
|
||||
|
||||
341
classes/SpriteSelector.py
Normal file
341
classes/SpriteSelector.py
Normal file
@@ -0,0 +1,341 @@
|
||||
from tkinter import filedialog, messagebox, Button, Canvas, Label, LabelFrame, Frame, PhotoImage, Scrollbar, Toplevel, ALL, NSEW, LEFT, BOTTOM, X, RIGHT, TOP, HORIZONTAL, EW, NS
|
||||
from glob import glob
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import shutil
|
||||
from urllib.parse import urlparse
|
||||
from urllib.request import urlopen
|
||||
from GuiUtils import ToolTips, set_icon, BackgroundTaskProgress
|
||||
from Rom import Sprite
|
||||
from Utils import is_bundled, local_path, output_path, open_file
|
||||
|
||||
class SpriteSelector(object):
|
||||
def __init__(self, parent, callback, adjuster=False):
|
||||
if is_bundled():
|
||||
self.deploy_icons()
|
||||
self.parent = parent
|
||||
self.window = Toplevel(parent)
|
||||
self.window.geometry("900x768")
|
||||
self.sections = []
|
||||
self.callback = callback
|
||||
self.adjuster = adjuster
|
||||
|
||||
self.window.wm_title("TAKE ANY ONE YOU WANT")
|
||||
self.window['padx'] = 5
|
||||
self.window['pady'] = 5
|
||||
self.all_sprites = []
|
||||
|
||||
def open_unofficial_sprite_dir(_evt):
|
||||
open_file(self.unofficial_sprite_dir)
|
||||
|
||||
official_frametitle = Label(self.window, text='Official Sprites')
|
||||
|
||||
unofficial_frametitle = Frame(self.window)
|
||||
title_text = Label(unofficial_frametitle, text="Unofficial Sprites")
|
||||
title_link = Label(unofficial_frametitle, text="(open)", fg="blue", cursor="hand2")
|
||||
title_text.pack(side=LEFT)
|
||||
title_link.pack(side=LEFT)
|
||||
title_link.bind("<Button-1>", open_unofficial_sprite_dir)
|
||||
|
||||
self.icon_section(official_frametitle, self.official_sprite_dir+'/*', 'Official sprites not found. Click "Update official sprites" to download them.')
|
||||
self.icon_section(unofficial_frametitle, self.unofficial_sprite_dir+'/*', 'Put sprites in the unofficial sprites folder (see open link above) to have them appear here.')
|
||||
|
||||
frame = Frame(self.window)
|
||||
frame.pack(side=BOTTOM, fill=X, pady=5)
|
||||
|
||||
button = Button(frame, text="Browse for file...", command=self.browse_for_sprite)
|
||||
button.pack(side=RIGHT, padx=(5, 0))
|
||||
|
||||
button = Button(frame, text="Update official sprites", command=self.update_official_sprites)
|
||||
button.pack(side=RIGHT, padx=(5, 0))
|
||||
|
||||
button = Button(frame, text="Default Link sprite", command=self.use_default_link_sprite)
|
||||
button.pack(side=LEFT, padx=(0, 5))
|
||||
|
||||
button = Button(frame, text="Random sprite", command=self.use_random_sprite)
|
||||
button.pack(side=LEFT, padx=(0, 5))
|
||||
|
||||
if adjuster:
|
||||
button = Button(frame, text="Current sprite from rom", command=self.use_default_sprite)
|
||||
button.pack(side=LEFT, padx=(0, 5))
|
||||
|
||||
set_icon(self.window)
|
||||
self.window.focus()
|
||||
|
||||
def icon_section(self, frame_label, path, no_results_label):
|
||||
self.frame = LabelFrame(self.window, labelwidget=frame_label, padx=5, pady=5)
|
||||
# self.canvas = Canvas(self.frame)
|
||||
|
||||
"""
|
||||
self.frame.grid_rowconfigure(0, weight=1)
|
||||
self.frame.grid_columnconfigure(0, weight=1)
|
||||
|
||||
xscrollbar = Scrollbar(self.frame, orient=HORIZONTAL)
|
||||
xscrollbar.grid(row=1, column=0, sticky=EW)
|
||||
|
||||
yscrollbar = Scrollbar(self.frame)
|
||||
yscrollbar.grid(row=0, column=1, sticky=NS)
|
||||
|
||||
self.canvas.configure(scrollregion=self.canvas.bbox(ALL),xscrollcommand=xscrollbar.set, yscrollcommand=yscrollbar.set)
|
||||
self.canvas.grid(row=0, column=0, sticky=NSEW)
|
||||
|
||||
xscrollbar.config(command=self.canvas.xview)
|
||||
yscrollbar.config(command=self.canvas.yview)
|
||||
"""
|
||||
|
||||
self.frame.pack(side=TOP, fill=X)
|
||||
|
||||
sprites = []
|
||||
|
||||
for file in glob(output_path(path)):
|
||||
sprites.append(Sprite(file))
|
||||
|
||||
sprites.sort(key=lambda s: str.lower(s.name or "").strip())
|
||||
|
||||
i = 0
|
||||
for sprite in sprites:
|
||||
image = get_image_for_sprite(sprite)
|
||||
if image is None:
|
||||
continue
|
||||
self.all_sprites.append(sprite)
|
||||
button = Button(self.frame, image=image, command=lambda spr=sprite: self.select_sprite(spr))
|
||||
ToolTips.register(button, sprite.name + ("\nBy: %s" % sprite.author_name if sprite.author_name else ""))
|
||||
button.image = image
|
||||
button.grid(row=i // 16, column=i % 16)
|
||||
i += 1
|
||||
|
||||
if i == 0:
|
||||
label = Label(self.frame, text=no_results_label)
|
||||
label.pack()
|
||||
|
||||
|
||||
def update_official_sprites(self):
|
||||
# need to wrap in try catch. We don't want errors getting the json or downloading the files to break us.
|
||||
self.window.destroy()
|
||||
self.parent.update()
|
||||
def work(task):
|
||||
resultmessage = ""
|
||||
successful = True
|
||||
|
||||
def finished():
|
||||
task.close_window()
|
||||
if successful:
|
||||
messagebox.showinfo("Sprite Updater", resultmessage)
|
||||
else:
|
||||
messagebox.showerror("Sprite Updater", resultmessage)
|
||||
SpriteSelector(self.parent, self.callback, self.adjuster)
|
||||
|
||||
try:
|
||||
task.update_status("Downloading official sprites list")
|
||||
with urlopen('https://alttpr.com/sprites') as response:
|
||||
sprites_arr = json.loads(response.read().decode("utf-8"))
|
||||
except Exception as e:
|
||||
resultmessage = "Error getting list of official sprites. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e)
|
||||
successful = False
|
||||
task.queue_event(finished)
|
||||
return
|
||||
|
||||
try:
|
||||
task.update_status("Determining needed sprites")
|
||||
current_sprites = [os.path.basename(file) for file in glob(self.official_sprite_dir+'/*')]
|
||||
official_sprites = [(sprite['file'], os.path.basename(urlparse(sprite['file']).path)) for sprite in sprites_arr]
|
||||
needed_sprites = [(sprite_url, filename) for (sprite_url, filename) in official_sprites if filename not in current_sprites]
|
||||
bundled_sprites = [os.path.basename(file) for file in glob(self.local_official_sprite_dir+'/*')]
|
||||
# todo: eventually use the above list to avoid downloading any sprites that we already have cached in the bundle.
|
||||
|
||||
official_filenames = [filename for (_, filename) in official_sprites]
|
||||
obsolete_sprites = [sprite for sprite in current_sprites if sprite not in official_filenames]
|
||||
except Exception as e:
|
||||
resultmessage = "Error Determining which sprites to update. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e)
|
||||
successful = False
|
||||
task.queue_event(finished)
|
||||
return
|
||||
|
||||
updated = 0
|
||||
for (sprite_url, filename) in needed_sprites:
|
||||
try:
|
||||
task.update_status("Downloading needed sprite %g/%g" % (updated + 1, len(needed_sprites)))
|
||||
target = os.path.join(self.official_sprite_dir, filename)
|
||||
with urlopen(sprite_url) as response, open(target, 'wb') as out:
|
||||
shutil.copyfileobj(response, out)
|
||||
except Exception as e:
|
||||
resultmessage = "Error downloading sprite. Not all sprites updated.\n\n%s: %s" % (type(e).__name__, e)
|
||||
successful = False
|
||||
updated += 1
|
||||
|
||||
deleted = 0
|
||||
for sprite in obsolete_sprites:
|
||||
try:
|
||||
task.update_status("Removing obsolete sprite %g/%g" % (deleted + 1, len(obsolete_sprites)))
|
||||
os.remove(os.path.join(self.official_sprite_dir, sprite))
|
||||
except Exception as e:
|
||||
resultmessage = "Error removing obsolete sprite. Not all sprites updated.\n\n%s: %s" % (type(e).__name__, e)
|
||||
successful = False
|
||||
deleted += 1
|
||||
|
||||
if successful:
|
||||
resultmessage = "official sprites updated successfully"
|
||||
|
||||
task.queue_event(finished)
|
||||
|
||||
BackgroundTaskProgress(self.parent, work, "Updating Sprites")
|
||||
|
||||
|
||||
def browse_for_sprite(self):
|
||||
sprite = filedialog.askopenfilename(
|
||||
filetypes=[("All Sprite Sources", (".zspr", ".spr", ".sfc", ".smc")),
|
||||
("ZSprite files", ".zspr"),
|
||||
("Sprite files", ".spr"),
|
||||
("Rom Files", (".sfc", ".smc")),
|
||||
("All Files", "*")])
|
||||
try:
|
||||
self.callback(Sprite(sprite))
|
||||
except Exception:
|
||||
self.callback(None)
|
||||
self.window.destroy()
|
||||
|
||||
|
||||
def use_default_sprite(self):
|
||||
self.callback(None)
|
||||
self.window.destroy()
|
||||
|
||||
def use_default_link_sprite(self):
|
||||
self.callback(Sprite.default_link_sprite())
|
||||
self.window.destroy()
|
||||
|
||||
def use_random_sprite(self):
|
||||
self.callback(random.choice(self.all_sprites) if self.all_sprites else None)
|
||||
self.window.destroy()
|
||||
|
||||
def select_sprite(self, spritename):
|
||||
self.callback(spritename)
|
||||
self.window.destroy()
|
||||
|
||||
|
||||
def deploy_icons(self):
|
||||
if not os.path.exists(self.unofficial_sprite_dir):
|
||||
os.makedirs(self.unofficial_sprite_dir)
|
||||
if not os.path.exists(self.official_sprite_dir):
|
||||
shutil.copytree(self.local_official_sprite_dir, self.official_sprite_dir)
|
||||
|
||||
@property
|
||||
def official_sprite_dir(self):
|
||||
if is_bundled():
|
||||
return output_path("sprites/official")
|
||||
return self.local_official_sprite_dir
|
||||
|
||||
@property
|
||||
def local_official_sprite_dir(self):
|
||||
return local_path("data/sprites/official")
|
||||
|
||||
@property
|
||||
def unofficial_sprite_dir(self):
|
||||
if is_bundled():
|
||||
return output_path("sprites/unofficial")
|
||||
return self.local_unofficial_sprite_dir
|
||||
|
||||
@property
|
||||
def local_unofficial_sprite_dir(self):
|
||||
return local_path("data/sprites/unofficial")
|
||||
|
||||
|
||||
def get_image_for_sprite(sprite):
|
||||
if not sprite.valid:
|
||||
return None
|
||||
height = 24
|
||||
width = 16
|
||||
|
||||
def draw_sprite_into_gif(add_palette_color, set_pixel_color_index):
|
||||
|
||||
def drawsprite(spr, pal_as_colors, offset):
|
||||
for y, row in enumerate(spr):
|
||||
for x, pal_index in enumerate(row):
|
||||
if pal_index:
|
||||
color = pal_as_colors[pal_index - 1]
|
||||
set_pixel_color_index(x + offset[0], y + offset[1], color)
|
||||
|
||||
add_palette_color(16, (40, 40, 40))
|
||||
shadow = [
|
||||
[0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
|
||||
]
|
||||
|
||||
drawsprite(shadow, [16], (2, 17))
|
||||
|
||||
palettes = sprite.decode_palette()
|
||||
for i in range(15):
|
||||
add_palette_color(i + 1, palettes[0][i])
|
||||
|
||||
body = sprite.decode16(0x4C0)
|
||||
drawsprite(body, list(range(1, 16)), (0, 8))
|
||||
head = sprite.decode16(0x40)
|
||||
drawsprite(head, list(range(1, 16)), (0, 0))
|
||||
|
||||
def make_gif(callback):
|
||||
gif_header = b'GIF89a'
|
||||
|
||||
gif_lsd = bytearray(7)
|
||||
gif_lsd[0] = width
|
||||
gif_lsd[2] = height
|
||||
gif_lsd[4] = 0xF4 # 32 color palette follows. transparant + 15 for sprite + 1 for shadow=17 which rounds up to 32 as nearest power of 2
|
||||
gif_lsd[5] = 0 # background color is zero
|
||||
gif_lsd[6] = 0 # aspect raio not specified
|
||||
gif_gct = bytearray(3 * 32)
|
||||
|
||||
gif_gce = bytearray(8)
|
||||
gif_gce[0] = 0x21 # start of extention blocked
|
||||
gif_gce[1] = 0xF9 # identifies this as the Graphics Control extension
|
||||
gif_gce[2] = 4 # we are suppling only the 4 four bytes
|
||||
gif_gce[3] = 0x01 # this gif includes transparency
|
||||
gif_gce[4] = gif_gce[5] = 0 # animation frrame delay (unused)
|
||||
gif_gce[6] = 0 # transparent color is index 0
|
||||
gif_gce[7] = 0 # end of gif_gce
|
||||
gif_id = bytearray(10)
|
||||
gif_id[0] = 0x2c
|
||||
# byte 1,2 are image left. 3,4 are image top both are left as zerosuitsamus
|
||||
gif_id[5] = width
|
||||
gif_id[7] = height
|
||||
gif_id[9] = 0 # no local color table
|
||||
|
||||
gif_img_minimum_code_size = bytes([7]) # we choose 7 bits, so that each pixel is represented by a byte, for conviennce.
|
||||
|
||||
clear = 0x80
|
||||
stop = 0x81
|
||||
|
||||
unchunked_image_data = bytearray(height * (width + 1) + 1)
|
||||
# we technically need a Clear code once every 125 bytes, but we do it at the start of every row for simplicity
|
||||
for row in range(height):
|
||||
unchunked_image_data[row * (width + 1)] = clear
|
||||
unchunked_image_data[-1] = stop
|
||||
|
||||
def add_palette_color(index, color):
|
||||
gif_gct[3 * index] = color[0]
|
||||
gif_gct[3 * index + 1] = color[1]
|
||||
gif_gct[3 * index + 2] = color[2]
|
||||
|
||||
def set_pixel_color_index(x, y, color):
|
||||
unchunked_image_data[y * (width + 1) + x + 1] = color
|
||||
|
||||
callback(add_palette_color, set_pixel_color_index)
|
||||
|
||||
def chunk_image(img):
|
||||
for i in range(0, len(img), 255):
|
||||
chunk = img[i:i + 255]
|
||||
yield bytes([len(chunk)])
|
||||
yield chunk
|
||||
|
||||
gif_img = b''.join([gif_img_minimum_code_size] + list(chunk_image(unchunked_image_data)) + [b'\x00'])
|
||||
|
||||
gif = b''.join([gif_header, gif_lsd, gif_gct, gif_gce, gif_id, gif_img, b'\x3b'])
|
||||
|
||||
return gif
|
||||
|
||||
gif_data = make_gif(draw_sprite_into_gif)
|
||||
image = PhotoImage(data=gif_data)
|
||||
|
||||
return image.zoom(2)
|
||||
1
classes/__init__.py
Normal file
1
classes/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# do nothing, just exist to make "classes" package
|
||||
108
gui/randomize/gameoptions.py
Normal file
108
gui/randomize/gameoptions.py
Normal file
@@ -0,0 +1,108 @@
|
||||
from tkinter import ttk, IntVar, StringVar, Button, Checkbutton, Entry, Frame, Label, OptionMenu, E, W, LEFT, RIGHT
|
||||
from classes.SpriteSelector import SpriteSelector
|
||||
|
||||
def gameoptions_page(parent):
|
||||
self = ttk.Frame(parent)
|
||||
|
||||
# Game Options options
|
||||
## Hints: Useful/Not useful
|
||||
self.hintsVar = IntVar()
|
||||
self.hintsVar.set(1) #set default
|
||||
hintsCheckbutton = Checkbutton(self, text="Include Helpful Hints", variable=self.hintsVar)
|
||||
hintsCheckbutton.pack(anchor=W)
|
||||
|
||||
## Disable BGM
|
||||
self.disableMusicVar = IntVar()
|
||||
disableMusicCheckbutton = Checkbutton(self, text="Disable music", variable=self.disableMusicVar)
|
||||
disableMusicCheckbutton.pack(anchor=W)
|
||||
|
||||
## L/R Quickswap
|
||||
self.quickSwapVar = IntVar()
|
||||
quickSwapCheckbutton = Checkbutton(self, text="L/R Quickswapping", variable=self.quickSwapVar)
|
||||
quickSwapCheckbutton.pack(anchor=W)
|
||||
|
||||
leftRomOptionsFrame = Frame(self)
|
||||
rightRomOptionsFrame = Frame(self)
|
||||
leftRomOptionsFrame.pack(side=LEFT)
|
||||
rightRomOptionsFrame.pack(side=RIGHT)
|
||||
|
||||
## Heart Color
|
||||
heartcolorFrame = Frame(leftRomOptionsFrame)
|
||||
heartcolorLabel = Label(heartcolorFrame, text='Heart color')
|
||||
heartcolorLabel.pack(side=LEFT)
|
||||
self.heartcolorVar = StringVar()
|
||||
self.heartcolorVar.set('red')
|
||||
heartcolorOptionMenu = OptionMenu(heartcolorFrame, self.heartcolorVar, 'red', 'blue', 'green', 'yellow', 'random')
|
||||
heartcolorOptionMenu.pack(side=RIGHT)
|
||||
heartcolorFrame.pack(anchor=E)
|
||||
|
||||
## Heart Beep Speed
|
||||
heartbeepFrame = Frame(leftRomOptionsFrame)
|
||||
heartbeepLabel = Label(heartbeepFrame, text='Heart Beep sound rate')
|
||||
heartbeepLabel.pack(side=LEFT)
|
||||
self.heartbeepVar = StringVar()
|
||||
self.heartbeepVar.set('normal')
|
||||
heartbeepOptionMenu = OptionMenu(heartbeepFrame, self.heartbeepVar, 'double', 'normal', 'half', 'quarter', 'off')
|
||||
heartbeepOptionMenu.pack(side=LEFT)
|
||||
heartbeepFrame.pack(anchor=E)
|
||||
|
||||
## Sprite selection
|
||||
spriteDialogFrame = Frame(leftRomOptionsFrame)
|
||||
baseSpriteLabel = Label(spriteDialogFrame, text='Sprite:')
|
||||
|
||||
self.spriteNameVar = StringVar()
|
||||
sprite = None
|
||||
def set_sprite(sprite_param):
|
||||
nonlocal sprite
|
||||
if sprite_param is None or not sprite_param.valid:
|
||||
sprite = None
|
||||
self.spriteNameVar.set('(unchanged)')
|
||||
else:
|
||||
sprite = sprite_param
|
||||
self.spriteNameVar.set(sprite.name)
|
||||
|
||||
set_sprite(None)
|
||||
self.spriteNameVar.set('(unchanged)')
|
||||
spriteEntry = Label(spriteDialogFrame, textvariable=self.spriteNameVar)
|
||||
|
||||
def SpriteSelect():
|
||||
SpriteSelector(parent, set_sprite)
|
||||
|
||||
spriteSelectButton = Button(spriteDialogFrame, text='...', command=SpriteSelect)
|
||||
|
||||
baseSpriteLabel.pack(side=LEFT)
|
||||
spriteEntry.pack(side=LEFT)
|
||||
spriteSelectButton.pack(side=LEFT)
|
||||
spriteDialogFrame.pack(anchor=E)
|
||||
|
||||
## Menu Speed
|
||||
fastMenuFrame = Frame(rightRomOptionsFrame)
|
||||
fastMenuLabel = Label(fastMenuFrame, text='Menu speed')
|
||||
fastMenuLabel.pack(side=LEFT)
|
||||
self.fastMenuVar = StringVar()
|
||||
self.fastMenuVar.set('normal')
|
||||
fastMenuOptionMenu = OptionMenu(fastMenuFrame, self.fastMenuVar, 'normal', 'instant', 'double', 'triple', 'quadruple', 'half')
|
||||
fastMenuOptionMenu.pack(side=LEFT)
|
||||
fastMenuFrame.pack(anchor=E)
|
||||
|
||||
## Overworld Palettes (not Enemizer)
|
||||
owPalettesFrame = Frame(rightRomOptionsFrame)
|
||||
owPalettesLabel = Label(owPalettesFrame, text='Overworld palettes')
|
||||
owPalettesLabel.pack(side=LEFT)
|
||||
self.owPalettesVar = StringVar()
|
||||
self.owPalettesVar.set('default')
|
||||
owPalettesOptionMenu = OptionMenu(owPalettesFrame, self.owPalettesVar, 'default', 'random', 'blackout')
|
||||
owPalettesOptionMenu.pack(side=LEFT)
|
||||
owPalettesFrame.pack(anchor=E)
|
||||
|
||||
## Underworld Palettes (not Enemizer)
|
||||
uwPalettesFrame = Frame(rightRomOptionsFrame)
|
||||
uwPalettesLabel = Label(uwPalettesFrame, text='Dungeon palettes')
|
||||
uwPalettesLabel.pack(side=LEFT)
|
||||
self.uwPalettesVar = StringVar()
|
||||
self.uwPalettesVar.set('default')
|
||||
uwPalettesOptionMenu = OptionMenu(uwPalettesFrame, self.uwPalettesVar, 'default', 'random', 'blackout')
|
||||
uwPalettesOptionMenu.pack(side=LEFT)
|
||||
uwPalettesFrame.pack(anchor=E)
|
||||
|
||||
return self
|
||||
Reference in New Issue
Block a user