diff --git a/SpellBurner.ico b/SpellBurner.ico new file mode 100644 index 0000000..1564c89 Binary files /dev/null and b/SpellBurner.ico differ diff --git a/SpellBurner.py b/SpellBurner.py index da45851..79971cf 100644 --- a/SpellBurner.py +++ b/SpellBurner.py @@ -1,7 +1,7 @@ # Burning Wheel - Spell Burner # By 2Shirt (Alan Mason) # -# Version 0.14a +# Version 1.0 from tkinter import * from tkinter import ttk from math import ceil, floor, log @@ -144,19 +144,26 @@ facetsMaBu = { weaponLength = ['Shortest', 'Short', 'Long', 'Longer', 'Longest'] -def getFacetTypes(): +def get_facet_types(): + """Return types of Facets as as list""" return sorted(facetsMaBu.keys()) -def getFacetOptions(facet): - return sorted(facetsMaBu[facet].keys()) +def get_facet_options(type): + """Return options of facet type 'type' as as list""" + return sorted(facetsMaBu[type].keys()) -def getFacetActions(facet, option): +def get_facet_actions(facet, option): + """Return actions of facet 'type', 'option' as an int()""" return facetsMaBu[facet][option]['Actions'] -def getFacetOb(facet, option): +def get_facet_ob(facet, option): + """Return obstacle of facet['type']['option'] as an int()""" return facetsMaBu[facet][option]['Ob'] -def getElementWeaponStats(elements, origins, aoes): +def get_weapon_stats(elements, origins, aoes): + """Return weapon stats, as a hash + + based on list(elements), list(origins), & list(aoes)""" weaponStats = {} for e in elements: try: @@ -184,7 +191,8 @@ def getElementWeaponStats(elements, origins, aoes): pass return weaponStats -def generateRange(min, max): +def generate_range(min, max): + """ Return a list of int()'s from min to max (inclusive)""" rangeList = [] if min > max: # Uh.... @@ -196,7 +204,10 @@ def generateRange(min, max): rangeList.append(str(i)) return rangeList -def roundMath(x): +def round_math(x): + """Round to the nearest int() + + (e.g. 1.5 -> 2.0, 2.5 -> 3.0, 2.4 -> 2.0)""" if (x - floor(x) >= 0.5): return floor(x) + 1 else: @@ -204,14 +215,16 @@ def roundMath(x): class Facet(): def reset(self, *args): + """Reset facet for a new spell""" self.actions.set('0') self.ob.set('0') self.option.set('') self.type.set(self.default) self.optionSelect['values'] = [] - self.updateOptions() + self.update_options() def destroy(self, *args): + """Destroy facet for a new spell""" try: self.obCombobox.destroy() except AttributeError: @@ -222,9 +235,10 @@ class Facet(): self.actionsLabel.destroy() self.actionsValueLabel.destroy() - def updateOptions(self, *args): + def update_options(self, *args): + """update obCombobox based on selected facet type""" try: - self.optionSelect['values'] = getFacetOptions(self.type.get()) + self.optionSelect['values'] = get_facet_options(self.type.get()) except KeyError: pass self.actions.set('0') @@ -236,9 +250,10 @@ class Facet(): self.obValueLabel.grid(column=6, row=self.row, sticky=W) except AttributeError: pass - self.frame.updateAll() + self.frame.update_all() - def updateStats(self, *args): + def update_stats(self, *args): + """update Actions on Ob based on selected facet type & option""" if self.option.get() == 'Anima': try: self.obValueLabel.destroy() @@ -248,29 +263,30 @@ class Facet(): self.obCombobox = ttk.Combobox(self.frame, textvariable=self.ob, width=2) self.obCombobox['values'] = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) self.obCombobox.state(['readonly']) - self.obCombobox.bind('<>', self.frame.updateAll) + self.obCombobox.bind('<>', self.frame.update_all) self.obCombobox.grid(column=6, row=self.row, sticky=W) else: try: self.obCombobox.destroy() except AttributeError: pass - self.ob.set(getFacetOb(self.type.get(), self.option.get())) + self.ob.set(get_facet_ob(self.type.get(), self.option.get())) self.obValueLabel = ttk.Label(self.frame, textvariable=self.ob) self.obValueLabel.grid(column=6, row=self.row, sticky=W) - self.actions.set(getFacetActions(self.type.get(), self.option.get())) - self.frame.updateAll() + self.actions.set(get_facet_actions(self.type.get(), self.option.get())) + self.frame.update_all() - def createWidgets(self): + def create_widgets(self): + """Create widgets upon instantiation""" self.typeSelect = ttk.Combobox(self.frame, textvariable=self.type, width=18) - self.typeSelect['values'] = getFacetTypes() + self.typeSelect['values'] = get_facet_types() self.typeSelect.state(['readonly']) - self.typeSelect.bind('<>', self.updateOptions) + self.typeSelect.bind('<>', self.update_options) self.typeSelect.grid(column=1, row=self.row, columnspan=2, sticky=(W, E)) self.optionSelect = ttk.Combobox(self.frame, textvariable=self.option) self.optionSelect.state(['readonly']) - self.optionSelect.bind('<>', self.updateStats) + self.optionSelect.bind('<>', self.update_stats) self.optionSelect.grid(column=3, row=self.row, columnspan=2, sticky=(W, E)) self.obLabel = ttk.Label(self.frame, text='Ob:', width=3) @@ -285,16 +301,28 @@ class Facet(): self.actionsValueLabel = ttk.Label(self.frame, textvariable=self.actions, width=3) self.actionsValueLabel.grid(column=8, row=self.row, sticky=W) - def getActions(self): + def get_actions(self): + """return Actions as float() + + Will return 0.0 if facet type/option not set""" return float(self.actions.get()) - def getOb(self): + def get_ob(self): + """return Ob as int() + + Will return 0 if facet type/option not set""" return float(self.ob.get()) - def getOption(self): + def get_option(self): + """return facet option as str() + + Will return '' if facet type not set""" return str(self.option.get()) - def getType(self): + def get_type(self): + """return facet type as str() + + Will return '' if facet type not set""" return str(self.type.get()) def __init__(self, frame, row, default=''): @@ -308,32 +336,34 @@ class Facet(): self.option = StringVar() self.type = StringVar() self.type.set(default) - self.createWidgets() + self.create_widgets() try: - self.optionSelect['values'] = getFacetOptions(self.type.get()) + self.optionSelect['values'] = get_facet_options(self.type.get()) except KeyError: pass class Distiller(): - def updateStats(self, *args): + def update_stats(self, *args): + """Update Actions/Ob totals based on facet selections""" self.obTmp = 0 self.actionsTmp = 0 for x in self.tobedistilled: try: - self.obTmp += x.getOb() - self.actionsTmp += x.getActions() + self.obTmp += x.get_ob() + self.actionsTmp += x.get_actions() except AttributeError: for y in x: - self.obTmp += y.getOb() - self.actionsTmp += y.getActions() + self.obTmp += y.get_ob() + self.actionsTmp += y.get_actions() if self.final: - self.ob.set(str(max(1,roundMath(self.obTmp/2)))) - self.actions.set(str(max(1,roundMath(self.actionsTmp/2)))) + self.ob.set(str(max(1,round_math(self.obTmp/2)))) + self.actions.set(str(max(1,round_math(self.actionsTmp/2)))) else: self.ob.set(str(self.obTmp/2)) self.actions.set(str(self.actionsTmp/2)) - def createWidgets(self): + def create_widgets(self): + """Create widgets upon instantiation""" ttk.Separator(self.frame, orient=HORIZONTAL).grid(column=1, row=self.row, columnspan=8, sticky=(W, E)) self.titleLabel = ttk.Label(self.frame, text=self.title, justify='right') @@ -353,10 +383,16 @@ class Distiller(): ttk.Separator(self.frame, orient=HORIZONTAL).grid(column=1, row=self.row + 2, columnspan=8, sticky=(W, E)) - def getActions(self): + def get_actions(self): + """return Actions as float() + + Will return 0.0 if facet type/option not set""" return float(self.actions.get()) - def getOb(self): + def get_ob(self): + """return Ob as float() + + Will return 0.0 if facet type/option not set""" return float(self.ob.get()) def __init__(self, frame, row, title, tobedistilled, final=False, *args): @@ -367,15 +403,19 @@ class Distiller(): self.final = final self.actions = StringVar() self.ob = StringVar() - self.createWidgets() - self.updateStats() + self.create_widgets() + self.update_stats() class MajorisSigil(): - def addSigil(self, *args): + def add_sigil(self, *args): + """Add an additional Majoris Sigil + + (and remove the '+' Button in the process)""" self.addButton.destroy() - self.frame.addMajorisSigil() + self.frame.add_majoris_sigil() def destroy(self, *args): + """destroy widgets for new Spell""" self.addButton.destroy() self.toggle.destroy() self.obCombobox.destroy() @@ -383,6 +423,7 @@ class MajorisSigil(): self.actionsEntry.destroy() def reset(self, *args): + """Reset widgets for new Spell""" self.enabled.set(False) self.ob.set('') self.obCombobox['values'] = ('') @@ -393,10 +434,11 @@ class MajorisSigil(): self.addButton.destroy() except: pass - self.addButton = ttk.Button(self.frame, text='+', command=self.addSigil, width=3) + self.addButton = ttk.Button(self.frame, text='+', command=self.add_sigil, width=3) self.addButton.grid(column=1, row=self.row) - def toggleSigil(self, *args): + def toggle_sigil(self, *args): + """Enable or Disable this Majoris Sigil""" if self.enabled.get(): self.ob.set('1') self.obCombobox.state(['!disabled']) @@ -410,9 +452,10 @@ class MajorisSigil(): self.obCombobox.state(['disabled']) self.actionsEntry.delete(0,'end') self.actionsEntry.state(['disabled']) - self.frame.updateAll() + self.frame.update_all() - def validateMultiplier(self, *args): + def validate_multiplier(self, *args): + """Handle monkey input for Actions Multiplier""" try: if (float(self.actionsEntry.get()) < 10): self.actionsEntry.delete(0,'end') @@ -426,24 +469,22 @@ class MajorisSigil(): except TypeError: self.actionsEntry.delete(0,'end') self.actionsEntry.insert(0, '10') - self.frame.updateAll() + self.frame.update_all() return 1 - def correctMultiplier(self, *args): - self.frame.updateAll() - - def createWidgets(self): - self.addButton = ttk.Button(self.frame, text='+', command=self.addSigil, width=3) + def create_widgets(self): + """Create widgets upon instantiation""" + self.addButton = ttk.Button(self.frame, text='+', command=self.add_sigil, width=3) self.addButton.grid(column=1, row=self.row) - self.toggle = Checkbutton(self.frame, text='Majoris', command=self.toggleSigil, + self.toggle = Checkbutton(self.frame, text='Majoris', command=self.toggle_sigil, variable=self.enabled, onvalue=True, offvalue=False) self.toggle.grid(column=2, row=self.row, sticky=W) self.obCombobox = ttk.Combobox(self.frame, textvariable=self.ob, width=2) self.obCombobox.state(['readonly']) self.obCombobox['values'] = ('') - self.obCombobox.bind('<>', self.frame.updateAll) + self.obCombobox.bind('<>', self.frame.update_all) self.obCombobox.grid(column=3, row=self.row, sticky=W) self.obCombobox.state(['disabled']) @@ -451,17 +492,23 @@ class MajorisSigil(): self.actionsLabel.grid(column=4, row=self.row, sticky=W) self.actionsEntry = ttk.Entry(self.frame, validate='focusout', - validatecommand=self.validateMultiplier, width=5) + validatecommand=self.validate_multiplier, width=5) self.actionsEntry.grid(column=5, row=self.row, sticky=W) self.actionsEntry.state(['disabled']) - def getMultiplier(self): + def get_multiplier(self): + """return Actions Multiplier as float() + + Will return 0.0 if Majoris Sigil is not set""" if self.enabled.get(): return float(self.actionsEntry.get()) else: return 1.0 - def getOb(self): + def get_ob(self): + """return Ob as int() + + Will return 0 if Majoris Sigil is not set""" if self.enabled.get(): return int(self.ob.get()) else: @@ -475,10 +522,11 @@ class MajorisSigil(): self.enabled = BooleanVar() self.enabled.set(False) self.ob = StringVar() - self.createWidgets() + self.create_widgets() class WeaponStats(): - def updateDisplay(self, *args): + def update_display(self, *args): + """Display weapon stats only if required facets are chosen""" if self.enabled: if not(self.prev): self.line = ttk.Separator(self.frame, orient=HORIZONTAL) @@ -520,25 +568,28 @@ class WeaponStats(): except AttributeError: pass - def updateStats(self, *args): + def update_stats(self, *args): + """Update weapon stats + + based on facets: 'Element', 'Origin', and 'Area of Effect'""" # Initialize self.prev = self.enabled & True # Not link? self.enabled = True self.spell = {} self.tmp = {} for f in self.frame.facets: - if f.getOption() == '': + if f.get_option() == '': pass - elif f.getType() in self.spell: - if f.getOption() in self.spell[f.getType()]: - self.spell[f.getType()][f.getOption()] += 1 + elif f.get_type() in self.spell: + if f.get_option() in self.spell[f.get_type()]: + self.spell[f.get_type()][f.get_option()] += 1 else: - self.spell[f.getType()][f.getOption()] = 1 + self.spell[f.get_type()][f.get_option()] = 1 else: - self.spell[f.getType()] = {} - self.spell[f.getType()][f.getOption()] = 1 + self.spell[f.get_type()] = {} + self.spell[f.get_type()][f.get_option()] = 1 try: - if self.spell[f.getType()][f.getOption()] > 1: + if self.spell[f.get_type()][f.get_option()] > 1: self.frame.valid = False except KeyError: pass @@ -554,7 +605,7 @@ class WeaponStats(): # Update Stats if self.enabled: - self.tmp = getElementWeaponStats( + self.tmp = get_weapon_stats( list(self.spell['Element']), list(self.spell['Origin']), list(self.spell['Area of Effect']) @@ -580,7 +631,7 @@ class WeaponStats(): self.frame.valid = False # Update display - self.updateDisplay() + self.update_display() def __init__(self, frame, row, *args): self.frame = frame @@ -595,7 +646,8 @@ class WeaponStats(): self.wVA = StringVar() class App(ttk.Frame): - def addExtraFacet(self, *args): + def add_extra_facet(self, *args): + """Add an extra Facet (limit 10)""" self.facets.append(Facet(self, self.extrafacetStartRow+len(self.facets[5:]))) # Update Distiller @@ -603,25 +655,28 @@ class App(ttk.Frame): (self.distiller1, self.distiller2, self.facets[4:]), final=True ) - self.configureGrid() + self.configure_grid() - def addMajorisSigil(self, *args): + def add_majoris_sigil(self, *args): + """Add an additional Majoris Sigil (limit 10)""" if len(self.majorisSigils) < self.majorisMaxRows: self.majorisSigils.append(MajorisSigil(self, self.majorisStartRow + len(self.majorisSigils))) - self.configureGrid() + self.configure_grid() - def configureGrid(self, *args): + def configure_grid(self, *args): + """Update window""" try: self.extraFacetButton.destroy() except: pass if len(self.facets[5:]) < self.extraFacetMaxRows: - self.extraFacetButton = ttk.Button(self, text='+', command=self.addExtraFacet, width=3) + self.extraFacetButton = ttk.Button(self, text='+', command=self.add_extra_facet, width=3) self.extraFacetButton.grid(column=1, row=19) for child in self.winfo_children(): child.grid_configure(padx=2, pady=2) def reset(self, *args): + """Reset all for a new Spell""" for f in self.facets[0:5]: f.reset() for f in self.facets[5:]: @@ -635,14 +690,15 @@ class App(ttk.Frame): self.minorisValue.set(0) self.compressValue.set(0) self.extendValue.set(0) - self.updateAll() - self.configureGrid() + self.update_all() + self.configure_grid() - def updateAll(self, *args): + def update_all(self, *args): + """Update all stats for this Spell""" ### Distillations ### - self.distiller1.updateStats() - self.distiller2.updateStats() - self.distiller3.updateStats() + self.distiller1.update_stats() + self.distiller2.update_stats() + self.distiller3.update_stats() ### Final Spell ### # Init Variables @@ -660,11 +716,11 @@ class App(ttk.Frame): self.majActTotal = 1 self.majObTotal = 0 for m in self.majorisSigils: - self.majObTotal += m.getOb() - self.majActTotal *= m.getMultiplier() + self.majObTotal += m.get_ob() + self.majActTotal *= m.get_multiplier() # After Final Distillation - self.subTotalAct = roundMath(self.distiller3.getActions()) - self.subTotalOb = roundMath(self.distiller3.getOb()) + self.subTotalAct = round_math(self.distiller3.get_actions()) + self.subTotalOb = round_math(self.distiller3.get_ob()) # Before rounding self.preAct = max(1, self.subTotalAct)*self.majActTotal*0.5**self.numCs self.preEs = self.subTotalOb @@ -724,9 +780,9 @@ class App(ttk.Frame): # Set limits if self.numCap == 0: self.capValue.set(False) - self.minorisCombobox['values'] = generateRange(self.minMin, self.maxMin) - self.compressCombobox['values'] = generateRange(self.minCs, self.maxCs) - self.extendCombobox['values'] = generateRange(self.minEs, self.maxEs) + self.minorisCombobox['values'] = generate_range(self.minMin, self.maxMin) + self.compressCombobox['values'] = generate_range(self.minCs, self.maxCs) + self.extendCombobox['values'] = generate_range(self.minEs, self.maxEs) # Misc Checks if self.preOb < ceil((self.preEs)/2): @@ -741,8 +797,8 @@ class App(ttk.Frame): self.finalActions.set(self.postAct) ### Weapon Stats ### - self.weapon.updateStats() - self.configureGrid() + self.weapon.update_stats() + self.configure_grid() ### Warnings ### if self.valid: @@ -753,7 +809,8 @@ class App(ttk.Frame): else: self.warningLabelText.set('[HOUSE RULED]') - def createWidgets(self): + def create_widgets(self): + """Create widgets upon instantiation""" # 1st Distillation self.facets.append(Facet(self, 0, 'Element')) self.facets.append(Facet(self, 1, 'Impetus')) @@ -773,7 +830,7 @@ class App(ttk.Frame): # 3rd Distillation self.facets.append(Facet(self, 10, 'Area of Effect')) - self.extraFacetButton = ttk.Button(self, text='+', command=self.addExtraFacet, width=3) + self.extraFacetButton = ttk.Button(self, text='+', command=self.add_extra_facet, width=3) self.extraFacetButton.grid(column=1, row=19) self.distiller3 = Distiller(self, 20, 'Final Distillation', @@ -785,7 +842,7 @@ class App(ttk.Frame): self.sigilsLabel = ttk.Label(self, text='Sigils').grid(column=1, row=24) # Adjustments - Cap & Minoris Sigil(S) - self.capCheckbutton = Checkbutton(self, text='Cap', command=self.updateAll, + self.capCheckbutton = Checkbutton(self, text='Cap', command=self.update_all, variable=self.capValue, onvalue=True, offvalue=False) self.capCheckbutton.grid(column=2, row=25, sticky=W) @@ -794,8 +851,8 @@ class App(ttk.Frame): self.minorisCombobox = ttk.Combobox(self, textvariable=self.minorisValue, width=2) self.minorisCombobox.state(['readonly']) - self.minorisCombobox['values'] = generateRange(0, 10) - self.minorisCombobox.bind('<>', self.updateAll) + self.minorisCombobox['values'] = generate_range(0, 10) + self.minorisCombobox.bind('<>', self.update_all) self.minorisCombobox.grid(column=5, row=25, sticky=W) # Adjustments - Majoris Sigil(S) @@ -807,8 +864,8 @@ class App(ttk.Frame): self.compressCombobox = ttk.Combobox(self, textvariable=self.compressValue, width=2) self.compressCombobox.state(['readonly']) - self.compressCombobox['values'] = generateRange(0, 10) - self.compressCombobox.bind('<>', self.updateAll) + self.compressCombobox['values'] = generate_range(0, 10) + self.compressCombobox.bind('<>', self.update_all) self.compressCombobox.grid(column=3, row=36, sticky=W) self.extendLabel = ttk.Label(self, text='Extensions') @@ -816,8 +873,8 @@ class App(ttk.Frame): self.extendCombobox = ttk.Combobox(self, textvariable=self.extendValue, width=2) self.extendCombobox.state(['readonly']) - self.extendCombobox['values'] = generateRange(0, 10) - self.extendCombobox.bind('<>', self.updateAll) + self.extendCombobox['values'] = generate_range(0, 10) + self.extendCombobox.bind('<>', self.update_all) self.extendCombobox.grid(column=5, row=36, sticky=W) # Final Spell Results @@ -864,7 +921,7 @@ class App(ttk.Frame): menu_file.add_command(label='Close', command=quit) menu_settings.add_checkbutton(label='Advanced Limiting', variable=self.advanceLimits, onvalue=True, offvalue=False, - command=self.updateAll + command=self.update_all ) self.capValue = BooleanVar() @@ -885,9 +942,9 @@ class App(ttk.Frame): self.finalActions = StringVar() self.finalActionsValue = 1 self.majorisSigils = [] - self.createWidgets() - self.updateAll() - self.configureGrid() + self.create_widgets() + self.update_all() + self.configure_grid() root = Tk() root.title('Spell Burner')