""" This file is part of RuneOptimizer. RuneOptimizer is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. RuneOptimizer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RuneOptimizer. If not, see . """ class PanelOptimizer(wx.Panel): """ The optimizer form Panel. Displays several optimization options to build and run the optimize command. Methods ------- select_unit(event=None, unit_id=None) Loads a unit info and enables optimizaton options. """ _selected_unit = None _team_ids = [] _unit_id_selector_index = [] _options_sizer = None _unit_choice = None _stat_grid = None _name_label = None _stars_label = None _level_label = None _id_label = None _priority_label = None _team_label = None _rune_label_list = None _min_stat_slid_list = None _min_stat_text_list = None _stat_checklist = None _set_choice_list = None _level_choice = None _inventory_check = None _teams_check_list = None _progress_gauge = None _timer = None _process = None def __init__(self, parent, id=wx.ID_ANY): """ Initializes the panel. Sets upt all the widgets. Parameters ---------- parent : wx.* Panel parent. id : int, optional ID for the panel (default wx.ID_ANY). """ # Parent constructor wx.Panel.__init__(self, parent=parent, id=id) # Prepare some fonts. monospace_font = wx.Font( pointSize=8, family=wx.FONTFAMILY_TELETYPE, style=wx.FONTSTYLE_NORMAL, weight=wx.FONTWEIGHT_NORMAL ) small_font = wx.Font( pointSize=7, family=wx.FONTFAMILY_DEFAULT, style=wx.FONTSTYLE_NORMAL, weight=wx.FONTWEIGHT_NORMAL ) bold_font = wx.Font( pointSize=10, family=wx.FONTFAMILY_DEFAULT, style=wx.FONTSTYLE_NORMAL, weight=wx.FONTWEIGHT_BOLD ) # Prepare the help icon icon_path = \ os.path.dirname(os.path.realpath(__file__)) + "/res/icon/help.png" if os.name == 'nt': icon_path = os.path.dirname(__file__) if icon_path == "": icon_path += "." icon_path += "\\res\\icon\\help.png" help_icon = wx.Bitmap(name=icon_path, type=wx.BITMAP_TYPE_PNG) # Sizer for all optimization options. Will be hidden until a unit is # selected. self._options_sizer = wx.BoxSizer(wx.VERTICAL) # Unit info box unit_info_box = wx.StaticBox( self, label="Select unit:", id=wx.ID_ANY, pos=(10, 0), size=(270, 530) ) # Get data from all units and populate the unit selector cursor = conn.execute("SELECT id, name FROM units ORDER BY name") unit_names = [] for row in cursor: unit_names.append(row[1]) self._unit_id_selector_index.append(row[0]) self._unit_choice = wx.Choice( parent=unit_info_box, id=wx.ID_ANY, pos=(10, 0), size=(200, 30), choices=unit_names ) self._unit_choice.Bind(wx.EVT_CHOICE, self.select_unit) # Stats table self._stat_grid = wx.grid.Grid( parent=unit_info_box, id=wx.ID_ANY, pos=(10, 30),size=(135, 220) ) self._stat_grid.CreateGrid( numRows=10, numCols=2 ) self._stat_grid.EnableEditing(False) self._stat_grid.SetDefaultCellAlignment( horiz=wx.ALIGN_RIGHT, vert=wx.ALIGN_CENTRE ) self._stat_grid.SetDefaultCellFont(monospace_font) self._stat_grid.SetColSize(col=0, width=50) self._stat_grid.SetColLabelValue(col=0, value="Base") self._stat_grid.SetColSize(col=1, width=50) self._stat_grid.SetColLabelValue(col=1, value="Curr.") self._stat_grid.SetRowLabelSize(width=35) self._stat_grid.SetColLabelSize(height=20) self._stat_grid.SetRowSize(row=0, height=20) self._stat_grid.SetRowSize(row=1, height=20) self._stat_grid.SetRowSize(row=2, height=20) self._stat_grid.SetRowSize(row=3, height=20) self._stat_grid.SetRowSize(row=4, height=20) self._stat_grid.SetRowSize(row=5, height=20) self._stat_grid.SetRowSize(row=6, height=20) self._stat_grid.SetRowSize(row=7, height=20) self._stat_grid.SetRowSize(row=8, height=20) self._stat_grid.SetRowSize(row=9, height=20) self._stat_grid.SetRowLabelValue(row=0, value=" HP") self._stat_grid.SetRowLabelValue(row=1, value="ATK") self._stat_grid.SetRowLabelValue(row=2, value="DEF") self._stat_grid.SetRowLabelValue(row=3, value="SPD") self._stat_grid.SetRowLabelValue(row=4, value="CRR") self._stat_grid.SetRowLabelValue(row=5, value="CRD") self._stat_grid.SetRowLabelValue(row=6, value="RES") self._stat_grid.SetRowLabelValue(row=7, value="ACC") self._stat_grid.SetRowLabelValue(row=8, value="EHP") self._stat_grid.SetRowLabelValue(row=9, value="DMG") self._name_label = wx.StaticText( parent=unit_info_box, id=wx.ID_ANY, label="", pos=(160, 40), size=(120, 25) ) self._name_label.SetFont(bold_font) self._stars_label = wx.StaticText( parent=unit_info_box, id=wx.ID_ANY, label="", pos=(160, 70), size=(120, 25) ) self._level_label = wx.StaticText( parent=unit_info_box, id=wx.ID_ANY, label="", pos=(160, 90), size=(120, 25) ) self._id_label = wx.StaticText( parent=unit_info_box, id=wx.ID_ANY, label="", pos=(160, 110), size=(120, 25) ) self._priority_label = wx.StaticText( parent=unit_info_box, id=wx.ID_ANY, label="", pos=(160, 130), size=(120, 25) ) self._teams_label = wx.StaticText( parent=unit_info_box, id=wx.ID_ANY, label="", pos=(160, 150), size=(120, 25) ) #Rune set list rune_box_list = [ wx.StaticBox( parent=unit_info_box, label="Slot1:", id=wx.ID_ANY, pos=(95, 260), size=(80, 115) ), wx.StaticBox( parent=unit_info_box, label="Slot2:", id=wx.ID_ANY, pos=(180, 260), size=(80, 115) ), wx.StaticBox( parent=unit_info_box, label="Slot3:", id=wx.ID_ANY, pos=(180, 380), size=(80, 115) ), wx.StaticBox( parent=unit_info_box, label="Slot4:", id=wx.ID_ANY, pos=(95, 380), size=(80, 115) ), wx.StaticBox( parent=unit_info_box, label="Slot5:", id=wx.ID_ANY, pos=(10, 380), size=(80, 115) ), wx.StaticBox( parent=unit_info_box, label="Slot6:", id=wx.ID_ANY, pos=(10, 260), size=(80, 115) ) ] for i in range(0, 6): rune_box_list[i].SetFont(monospace_font) self._rune_label_list = [ wx.StaticText( parent=rune_box_list[0], id=wx.ID_ANY, label="", pos=(0, 0), size=(80, 115) ), wx.StaticText( parent=rune_box_list[1], id=wx.ID_ANY, label="", pos=(0, 0), size=(80, 115) ), wx.StaticText( parent=rune_box_list[2], id=wx.ID_ANY, label="", pos=(0, 0), size=(80, 115) ), wx.StaticText( parent=rune_box_list[3], id=wx.ID_ANY, label="", pos=(0, 0), size=(80, 115) ), wx.StaticText( parent=rune_box_list[4], id=wx.ID_ANY, label="", pos=(0, 0), size=(80, 115) ), wx.StaticText( parent=rune_box_list[5], id=wx.ID_ANY, label="", pos=(0, 0), size=(80, 115) ) ] # Min stats min_stat_box = wx.StaticBox( parent=self, label="Min. stats:", id=wx.ID_ANY, pos=(300, 0), size=(240, 300) ) min_stat_help = wx.BitmapButton( parent=self, id=wx.ID_ANY, bitmap=help_icon, pos=(370, 0), size=(20, 20) ) min_stat_help.Bind( wx.EVT_MOTION, lambda event: self._show_help( event, text= "These are the minimum stats to aim for during the optimization." ) ) min_stat_help.Bind( wx.EVT_BUTTON, lambda event: self._open_help( event, title="Minimum stats", text= "These are the minimum stats to aim for during the " + "optimization.\n\nA rune combination will not be accepted " + "unless every stat has a value equal or higher than those " + "defined here." ) ) wx.StaticText( parent=min_stat_box, label="HP", id=wx.ID_ANY, pos=(0, 0), size=(30, 25) ) wx.StaticText( parent=min_stat_box, label="ATK", id=wx.ID_ANY, pos=(0, 25), size=(30, 25) ) wx.StaticText( parent=min_stat_box, label="DEF", id=wx.ID_ANY, pos=(0, 50), size=(30, 25) ) wx.StaticText( parent=min_stat_box, label="SPD", id=wx.ID_ANY, pos=(0, 75), size=(30, 25) ) wx.StaticText( parent=min_stat_box, label="CRR", id=wx.ID_ANY, pos=(0, 100), size=(30, 25) ) wx.StaticText( parent=min_stat_box, label="CRD", id=wx.ID_ANY, pos=(0, 125), size=(30, 25) ) wx.StaticText( parent=min_stat_box, label="RES", id=wx.ID_ANY, pos=(0, 150), size=(30, 25) ) wx.StaticText( parent=min_stat_box, label="ACC", id=wx.ID_ANY, pos=(0, 175), size=(30, 25) ) wx.StaticText( parent=min_stat_box, label="EHP", id=wx.ID_ANY, pos=(0, 200), size=(30, 25) ) wx.StaticText( parent=min_stat_box, label="DMG", id=wx.ID_ANY, pos=(0, 225), size=(30, 25) ) self._min_stat_slid_list = [ wx.Slider( parent=min_stat_box, id=wx.ID_ANY, pos=(30, 0), size=(120, 25), name="slid0" ), wx.Slider( parent=min_stat_box, id=wx.ID_ANY, pos=(30, 25), size=(120, 25), name="slid1" ), wx.Slider( parent=min_stat_box, id=wx.ID_ANY, pos=(30, 50), size=(120, 25), name="slid2" ), wx.Slider( parent=min_stat_box, id=wx.ID_ANY, pos=(30, 75), size=(120, 25), name="slid3" ), wx.Slider( parent=min_stat_box, id=wx.ID_ANY, pos=(30, 100), size=(120, 25), name="slid4" ), wx.Slider( parent=min_stat_box, id=wx.ID_ANY, pos=(30, 125), size=(120, 25), name="slid5" ), wx.Slider( parent=min_stat_box, id=wx.ID_ANY, pos=(30, 150), size=(120, 25), name="slid6" ), wx.Slider( parent=min_stat_box, id=wx.ID_ANY, pos=(30, 175), size=(120, 25), name="slid7" ), wx.Slider( parent=min_stat_box, id=wx.ID_ANY, pos=(30, 200), size=(120, 25), name="slid8" ), wx.Slider( parent=min_stat_box, id=wx.ID_ANY, pos=(30, 225), size=(120, 25), name="slid9" ) ] for i in range(0, 10): self._min_stat_slid_list[i].SetMin(0) self._min_stat_slid_list[i].SetMax(0) self._min_stat_slid_list[i].SetValue(0) self._min_stat_slid_list[i].Bind( wx.EVT_SCROLL, self._min_stat_change_by_slider ) self._min_stat_text_list = [ wx.TextCtrl( parent=min_stat_box, id=wx.ID_ANY, value="", pos=(155, 0), size=(65, 25), name="tx0", style=wx.TE_RIGHT|wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB ), wx.TextCtrl( parent=min_stat_box, id=wx.ID_ANY, value="", pos=(155, 25), size=(65, 25), name="tx1", style=wx.TE_RIGHT|wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB ), wx.TextCtrl( parent=min_stat_box, id=wx.ID_ANY, value="", pos=(155, 50), size=(65, 25), name="tx2", style=wx.TE_RIGHT|wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB ), wx.TextCtrl( parent=min_stat_box, id=wx.ID_ANY, value="", pos=(155, 75), size=(65, 25), name="tx3", style=wx.TE_RIGHT|wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB ), wx.TextCtrl( parent=min_stat_box, id=wx.ID_ANY, value="", pos=(155, 100), size=(65, 25), name="tx4", style=wx.TE_RIGHT|wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB ), wx.TextCtrl( parent=min_stat_box, id=wx.ID_ANY, value="", pos=(155, 125), size=(65, 25), name="tx5", style=wx.TE_RIGHT|wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB ), wx.TextCtrl( parent=min_stat_box, id=wx.ID_ANY, value="", pos=(155, 150), size=(65, 25), name="tx6", style=wx.TE_RIGHT|wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB ), wx.TextCtrl( parent=min_stat_box, id=wx.ID_ANY, value="", pos=(155, 175), size=(65, 25), name="tx7", style=wx.TE_RIGHT|wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB ), wx.TextCtrl( parent=min_stat_box, id=wx.ID_ANY, value="", pos=(155, 200), size=(65, 25), name="tx8", style=wx.TE_RIGHT|wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB ), wx.TextCtrl( parent=min_stat_box, id=wx.ID_ANY, value="", pos=(155, 225), size=(65, 25), name="tx9", style=wx.TE_RIGHT|wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB ) ] for i in range(0, 9): self._min_stat_text_list[i].Bind( wx.EVT_TEXT, self._min_stat_change_by_text ) wx.Button( parent=min_stat_box, id=wx.ID_ANY, pos=(10, 250), size=(100, 20), style=wx.LC_REPORT, label="Reset all" ).Bind(wx.EVT_BUTTON, self._reset_stats) wx.Button( parent=min_stat_box, id=wx.ID_ANY, pos=(120, 250), size=(100, 20), style=wx.LC_REPORT, label="Adapt all" ).Bind(wx.EVT_BUTTON, self._adapt_stats) self._options_sizer.Add(min_stat_box) self._options_sizer.Add(min_stat_help) # Allowed main stats for even slots names = [ "HP ", "HP% ", "ATK ", "ATK%", "DEF ", "DEF%", "SPD ", "CRR ", "CRD ", "RES ", "ACC " ] stat_box = wx.StaticBox( self, id=wx.ID_ANY, label="Main stats:", pos=(550, 70), size=(110, 315) ) stat_help = wx.BitmapButton( parent=self, id=wx.ID_ANY, bitmap=help_icon, pos=(630, 70), size=(20, 20) ) stat_help.Bind( wx.EVT_MOTION, lambda event: self._show_help( event, text="Main stats for runes in slots 2, 4 and 6." ) ) stat_help.Bind( wx.EVT_BUTTON, lambda event: self._open_help( event, title="Main stats", text= "Stats for runes in slots 2, 4 and 6.\n\n" + + "Runes in slots 2, 4 and 6 can only have one of the main " + "stats selected here, so make sure to select at least one " + "stat that can appear as main stat in each of the three " + "slots. This has no effect for runes in slots 1, 3 and 5." ) ) self._stat_checklist = wx.CheckListBox( parent=stat_box, id=wx.ID_ANY, pos=(5, 5), size=(100, 285), choices=names ) self._options_sizer.Add(stat_box) self._options_sizer.Add(stat_help) # Rune sets set_names = [ "", "ENERGY ", "GUARD ", "SWIFT ", "BLADE ", "RAGE ", "FOCUS ", "ENDURE ", "FATAL ", "DESPAIR", "VAMPIRE", "VIOLENT", "NEMESIS", "WILL ", "SHIELD ", "REVENGE", "DESTROY", "FIGHT ", "DETERMI", "ENHANCE", "ACCURAC", "TOLERAN" ] set_box = wx.StaticBox( self, label="Rune Sets:", id=wx.ID_ANY, pos=(550, 0), size=(330, 60) ) set_help = wx.BitmapButton( parent=self, id=wx.ID_ANY, bitmap=help_icon, pos=(620, 0), size=(20, 20) ) set_help.Bind( wx.EVT_MOTION, lambda event: self._show_help( event, text="The unit must have at least these rune sets." ) ) set_help.Bind( wx.EVT_BUTTON, lambda event: self._open_help( event, title="Rune sets", text= "The unit must have at least these rune sets.\n\n" + + "A rune combination will not be accepted unless it contains " + "at least these sets. At least one set must be selected, and " + "up to three can be specified if they do they do not sum more " + "than 6 runes." ) ) self._set_choice_list = [ wx.Choice( parent=set_box, id=wx.ID_ANY, pos=(5, 0), size=(100, 30), choices=set_names ), wx.Choice( parent=set_box, id=wx.ID_ANY, pos=(110, 0), size=(100, 30), choices=set_names ), wx.Choice( parent=set_box, id=wx.ID_ANY, pos=(215, 0), size=(100, 30), choices=set_names ) ] self._options_sizer.Add(set_box) self._options_sizer.Add(set_help) # Rune level selector _level_box = wx.StaticBox( parent=self, label="Rune Level:", id=wx.ID_ANY, pos=(550, 390), size=(110, 60) ) _level_help = wx.BitmapButton( parent=self, id=wx.ID_ANY, bitmap=help_icon, pos=(635, 390), size=(20, 20) ) _level_help.Bind( wx.EVT_MOTION, lambda event: self._show_help( event, text= "Unit can be considered to be at it's current level, at level " + "12 or level 15." ) ) _level_help.Bind( wx.EVT_BUTTON, lambda event: self._open_help( event, title="Rune level", text= "Unit can be considered to be at it's current level, at level " + "12 or level 15.\n\n" + "When calculating optimizations, the optimizer can consider " + "the stats a rune will have when it is powered up to level 12 " + "or 15. This is usefull to get more results using the runes " + "you havn't yer powered up.\n\n Note that this is only " + "applied for the values of the rune main stats, and possible " + "new substats added during power ups are not ocnsidered." ) ) self._level_choice = wx.Choice( parent=_level_box, id=wx.ID_ANY, pos=(5, 0), choices=["Current", "+ 12", " + 15"] ) self._options_sizer.Add(_level_box) self._options_sizer.Add(_level_help) _opt_set_box = wx.StaticBox( self, label="Other Rune Sets:", id=wx.ID_ANY, pos=(670, 70), size=(220, 315) ) _opt_set_help = wx.BitmapButton( parent=self, id=wx.ID_ANY, bitmap=help_icon, pos=(790, 70), size=(20, 20) ) _opt_set_help.Bind( wx.EVT_MOTION, lambda event: self._show_help( event, text="Other rune sets that can be used for the unit." ) ) _opt_set_help.Bind( wx.EVT_BUTTON, lambda event: self._open_help( event, title="Other rune sets", text= "If the sets selected in the 'Rune sets' section dont complete " + "a 6 rune pack, any rune of the selected sets selected here " + "will be used to fill out the blanks.\n\nRunes not selected " + "neither in the 'Rune sets' section nor here will not be " + "considered during thhe optimization. There is no need to " + "select a set here if it's already selected in the 'Rune " + "sets' section.\n\n Note that sets selected here are not " + "guaranteed to form a full set if the option 'Allow broken " + "sets' is checked (for example, marking 'Energy' and 'Guard' " + "here, while also marking 'Allow broken sets' can end up with " + "the unit having one rune of each, thus not getting any of " + "the set bonuses)." ) ) self._options_sizer.Add(_opt_set_box) self._options_sizer.Add(_opt_set_help) self._opt_set_checklist_list = [ wx.CheckListBox( parent=_opt_set_box, id=wx.ID_ANY, pos=(5, 5), size=(100, 285), choices=set_names[1:12] ), wx.CheckListBox( parent=_opt_set_box, id=wx.ID_ANY, pos=(105, 5), size=(100, 285), choices=set_names[12:25] ) ] # Team list teams_formatted = [] for team in teams.values(): self._team_ids.append(team.id) teams_formatted.append(team.name + " (" + str(team.priority) + ")") teams_box = wx.StaticBox( parent=self, label="Exclude runes from units in teams", id=wx.ID_ANY, pos=(300, 300), size=(240, 230) ) teams_help = wx.BitmapButton( parent=self, id=wx.ID_ANY, bitmap=help_icon, pos=(515, 300), size=(20, 20) ) teams_help.Bind( wx.EVT_MOTION, lambda event: self._show_help( event, text="Exclude runes from units in teams selected teams." ) ) teams_help.Bind( wx.EVT_BUTTON, lambda event: self._open_help( event, title="Exclude runes from units in teams.", text= "During the optimization, no rune will be considered if it's " + "equiped by any unit in any of the selected teams.\n\n Note " + "that runes equiped to the unit being optimized will always " + "be considered, even if the unit is on a selected team." ) ) self._options_sizer.Add(teams_box) self._options_sizer.Add(teams_help) self._teams_check_list = wx.CheckListBox( parent=teams_box, id=wx.ID_ANY, pos=(5, 5), size=(230, 170), choices=teams_formatted ) wx.Button( parent=teams_box, id=wx.ID_ANY, pos=(10, 180), size=(105, 20), label="Select all" ).Bind(wx.EVT_BUTTON, self._select_all_teams) btNoTeams = wx.Button( parent=teams_box, id=wx.ID_ANY, pos=(120, 180), size=(105, 20), label="Deselect all" ).Bind(wx.EVT_BUTTON, self._deselect_all_teams) # Broken sets option self._broken_check = wx.CheckBox( parent=self, id=wx.ID_ANY, label="Allow broken sets", pos=(670, 400), size=(180, 20) ) _broken_help = wx.BitmapButton( parent=self, id=wx.ID_ANY, bitmap=help_icon, pos=(850, 400), size=(20, 20) ) _broken_help.Bind( wx.EVT_MOTION, lambda event: self._show_help( event, text="Allow runes in 'Other Rune Sets' to form broken sets." ) ) _broken_help.Bind( wx.EVT_BUTTON, lambda event: self._open_help( event, title="Allow broken sets.", text= "Allows the optimizer to consider broken sets using the runes " + "selected in 'Other Rune Sets'.\n\n This will probably get " + "more results with better runes, at the expense of not " + "getting rune set bonuses. Runes selected in 'Rune Sets' will " + "always form complete sets." ) ) self._options_sizer.Add(self._broken_check) self._options_sizer.Add(_broken_help) # Inventory only option self._inventory_check = wx.CheckBox( parent=self, id=wx.ID_ANY, label="Only runes in storage", pos=(670, 430), size=(180, 20) ) _inventory_help = wx.BitmapButton( parent=self, id=wx.ID_ANY, bitmap=help_icon, pos=(850, 430), size=(20, 20) ) _inventory_help.Bind( wx.EVT_MOTION, lambda event: self._show_help( event, text="Don use runes assigned to any unit." ) ) _inventory_help.Bind( wx.EVT_BUTTON, lambda event: self._open_help( event, title="Only runes in storage.", text= "When selected, the optimizer will consider only the runes in " + "storage, and it will not use any rune assigned to any other " + "unit.\n\n Note that runes equiped by the unit being " + "optimized will always be considered." ) ) self._options_sizer.Add(self._inventory_check) self._options_sizer.Add(_inventory_help) # Threads slider thread_label = wx.StaticText( parent=self, id=wx.ID_ANY, label="Threads:", pos=(550, 470), size=(180, 45) ) thread_help = wx.BitmapButton( parent=self, id=wx.ID_ANY, bitmap=help_icon, pos=(570, 490), size=(20, 20) ) thread_help.Bind( wx.EVT_MOTION, lambda event: self._show_help( event, text= "How many threads to use. The more, the faster the optimization." ) ) thread_help.Bind( wx.EVT_BUTTON, lambda event: self._open_help( event, title="Threads.", text= "Select how many threads to use during optimization.\n\n As a " + "rule, the more threads used, the faster the optimization " + "will be, but for optimal results, select as many threads as " + "CPU cores your computer has." ) ) self._thread_slider = wx.Slider( parent=self, id=wx.ID_ANY, pos=(620, 450), size=(200, 65), style=wx.SL_AUTOTICKS|wx.SL_LABELS|wx.SL_SELRANGE ) self._thread_slider.SetMin(1) self._thread_slider.SetMax(8) cores = multiprocessing.cpu_count() if cores < 1: cores = 1 if cores > 8: cores = 8; self._thread_slider.SetValue(cores) self._options_sizer.Add(thread_label) self._options_sizer.Add(self._thread_slider) self._options_sizer.Add(thread_help) # Button to start btOptimize = wx.Button( parent=self, id=wx.ID_ANY, pos=(750, 550), size=(100, 40), style=wx.LC_REPORT, label="OPTIMIZE" ) self._options_sizer.Add(btOptimize) self.Bind(wx.EVT_BUTTON, self._start_optimization, btOptimize) # Progress bar self._progress_gauge = wx.Gauge( parent=self, id=wx.ID_ANY, range=20, pos=(50, 535), size=(650, 40), style=wx.GA_HORIZONTAL ) self._options_sizer.Add(self._progress_gauge) # By default, hide all optimization options self._options_sizer.ShowItems(False) def _show_help(self, event, text=None): """Shows a help tooltip. Parameters ---------- event : wxEvent The event that triggered the call. text : string, optional The text for the tooltip. """ event.GetEventObject().SetToolTip(wx.ToolTip(text)) def _open_help(self, event, title=None, text=None): """Shows a help dialog. Parameters ---------- event : wxEvent The event that triggered the call. title : string, optional The text for the dialog title. text : string, optional The text for the dialog body. """ wx.MessageBox( parent=self, message=text, caption=title, style=wx.ICON_INFORMATION ) def _select_all_teams(self, event = None): """Selects all teams in the list. Parameters ---------- event : wxEvent, optional The event that triggered the call (default is None). """ for i in range(0, len(self._team_ids)): self._teams_check_list.Check(i, True) def _deselect_all_teams(self, event = None): """Deselects all teams in the list. Parameters ---------- event : wxEvent, optional The event that triggered the call (default is None). """ for i in range(0, len(self._team_ids)): self._teams_check_list.Check(i, False) def select_unit(self, event=None, unit_id=None): """Loads a unit info and enables optimizaton options. Called when a unit is selected in _unit_choice. If called from an an event, the unit selected in _unit_choice gets priority. When manually called, it uses unitId, so it must be set beforehand. Parameters ---------- event : wxEvent, optional The event that triggered the call (default is None). """ # If its called from an event, it means a unit has been selected in this # panel selector. if unit_id is None: unit_id = \ self._unit_id_selector_index[self._unit_choice.GetSelection()] # It it was not called from an event, and unit_id has value else: for i in range(0, len(self._unit_id_selector_index)): if self._unit_id_selector_index[i] == unit_id: self._unit_choice.SetSelection(i) break self._selected_unit = units[unit_id] # Set unit info labels self._name_label.SetLabel(self._selected_unit.name) stars_label_text = "" for i in range(0, self._selected_unit.stars): stars_label_text += "\u272D" self._stars_label.SetLabel(stars_label_text) self._level_label.SetLabel("Lv." + str(self._selected_unit.level)) self._id_label.SetLabel("#" + self._selected_unit.id) self._priority_label.SetLabel( "Priority: " + str(self._selected_unit.priority) ) teams_label_text = "" if len(self._selected_unit.teams) == 0: teams_label_text = "In no teams." elif len(self._selected_unit.teams) == 1: teams_label_text = "In 1 team." else: teams_label_text = \ "In " + str(len(self._selected_unit.teams)) + " teams." self._teams_label.SetLabel(teams_label_text) # Set sliders max values self._min_stat_slid_list[0].SetMax(100000) #HP self._min_stat_slid_list[1].SetMax(5000) #ATK self._min_stat_slid_list[2].SetMax(5000) #DEF self._min_stat_slid_list[3].SetMax(500) #SPD self._min_stat_slid_list[4].SetMax(100) #CRR self._min_stat_slid_list[5].SetMax(500) #CRD self._min_stat_slid_list[6].SetMax(100) #RES self._min_stat_slid_list[7].SetMax(85) #ACC self._min_stat_slid_list[8].SetMax(500000) #EHP self._min_stat_slid_list[9].SetMax(8000) #DMG stat_base_values = self._selected_unit.base_stats.values() stat_curr_values = self._selected_unit.stats.values() for i in range (0, 10): self._min_stat_slid_list[i].SetMin(stat_base_values[i]) self._min_stat_slid_list[i].SetValue(stat_curr_values[i]) self._min_stat_text_list[i].SetValue(str(stat_curr_values[i])) stat_str = str(stat_base_values[i]) if i in [4, 5, 6, 7]: # CRR, CRD, RES, ACC stat_str = stat_str + "%" else: stat_str = stat_str + " " self._stat_grid.SetCellValue(row=i, col=0, s=stat_str) stat_str = str(stat_curr_values[i]) if i in [4, 5, 6, 7]: # CRR, CRD, RES, ACC stat_str = stat_str + "%" else: stat_str = stat_str + " " self._stat_grid.SetCellValue(row=i, col=1, s=stat_str) # Populate the runes for i in range(0, 6): self._rune_label_list[i].SetLabel("") i = 0 current_equiped_stats = [0, 0, 0] current_equiped_set_list = [0] * 23; for rune in self._selected_unit.runes: current_equiped_set_list[rune.type] += 1 label = "" label = label + rune.type_name + "\n" # Read rune stats j = -1 for stat in rune.stats: if (rune.slot == 2 and stat.slot == -1): current_equiped_stats[0] = stat.stat elif (rune.slot == 4 and stat.slot == -1): current_equiped_stats[1] = stat.stat elif (rune.slot == 6 and stat.slot == -1): current_equiped_stats[2] = stat.stat while (j != stat.slot): label = label + "\n" # No stat, empty line j = j + 1; label = label + \ stat.name + str(stat.value).rjust(4) if stat.grind > 0: label = label + " +" + str(stat.grind) self._rune_label_list[i].SetLabel(label) i = i + 1 # Try to infer data to set the default options, reset the rest # Except the team list, rune level and storage: never reset those. self._stat_checklist.SetCheckedItems(()) for i in range(0, 3): if current_equiped_stats[i] == 1: # HP self._stat_checklist.Check(0, True) elif current_equiped_stats[i] == 2: # HP% self._stat_checklist.Check(1, True) elif current_equiped_stats[i] == 3: # ATK self._stat_checklist.Check(2, True) elif current_equiped_stats[i] == 4: # ATK% self._stat_checklist.Check(3, True) elif current_equiped_stats[i] == 5: # DEF self._stat_checklist.Check(4, True) elif current_equiped_stats[i] == 6: # DEF% self._stat_checklist.Check(5, True) elif current_equiped_stats[i] == 8: # SPD self._stat_checklist.Check(6, True) elif current_equiped_stats[i] == 9: # CRR self._stat_checklist.Check(7, True) elif current_equiped_stats[i] == 10: # CRD self._stat_checklist.Check(8, True) elif current_equiped_stats[i] == 11: # RES self._stat_checklist.Check(9, True) elif current_equiped_stats[i] == 12: # ACC self._stat_checklist.Check(10, True) current_equiped_sets = [-1, -1, -1] j = 0 for i in range(0, 23): if j < 3: # If a set of 2 has 4 or 2: if i in [ 1, 2, 4, 6, 7, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 ]: if current_equiped_set_list[i] >= 4: current_equiped_sets[j] = i - 1 current_equiped_sets[j + 1] = i - 1 j += 2 elif current_equiped_set_list[i] >= 2: current_equiped_sets[j] = i - 1 j += 1 # If a set of 4 has 4 elif i in [3, 5, 8, 10, 11, 13]: if current_equiped_set_list[i] >= 4: current_equiped_sets[j] = i - 1 j += 1 # Rune set IDs 9 and 12 dont exist, so do a little trick with indexes. for i in range(0, 3): #if current_equiped_sets[i] != 0: actual_id = current_equiped_sets[i] + 1 if (actual_id > 8): actual_id -= 1 if (actual_id > 11): actual_id -= 1 self._set_choice_list[i].SetSelection(actual_id) # Clear all optional sets self._opt_set_checklist_list[0].SetCheckedItems(()) self._opt_set_checklist_list[1].SetCheckedItems(()) self._options_sizer.ShowItems(True) def _start_optimization(self, event): """ Prepares and runs a command optimization. Once is done, switches to the results view. Parameters ---------- event : wxEvent, optional The event that triggered the call (default is None). """ # Example call: # ../RuneOptimizer optimize 7223811472 -l 15 #-e rage,blade --stats atk,crr,crd -h 10000 -f 10 # TODO: Executable name for windows. command = "runeoptimizer optimize " command += self._selected_unit.id level = self._level_choice.GetSelection() if level == 1: level = "12" elif level == 2: level = "15" else: level = "current" command += (" --level " + level) sets = "" for i in range (0, 3): selected = self._set_choice_list[i].GetString( self._set_choice_list[i].GetSelection() ).upper().replace(" ", ""); for j in range(0, 22): name = SET_NAMES[j].upper() if len(name) > 7: name = name[0:7] if selected == name: sets += SET_NAMES[j].lower() + "," if len(sets) > 0: sets = sets[:-1] # TODO: ELSE ERROR command += (" --sets " + sets) stats = "" for s in self._stat_checklist.GetCheckedItems(): if s == 0: stats += "hpflat," elif s == 1: stats += "hp," elif s == 2: stats += "atkflat," elif s == 3: stats += "atk," elif s == 4: stats += "defflat," elif s == 5: stats += "def," elif s == 6: stats += "spd," elif s == 7: stats += "crr," elif s == 8: stats += "crd," elif s == 9: stats += "res," elif s == 10: stats += "acc," if len(stats) > 0: stats = stats[:-1] # TODO: ELSE ERROR # Optional sets opt_sets = "" for s in self._opt_set_checklist_list[0].GetCheckedItems(): if s == 0: opt_sets += "energy," elif s == 1: opt_sets += "guard," elif s == 2: opt_sets += "swift," elif s == 3: opt_sets += "blade," elif s == 4: opt_sets += "rage," elif s == 5: opt_sets += "focus," elif s == 6: opt_sets += "endure," elif s == 7: opt_sets += "fatal," elif s == 8: opt_sets += "despair," elif s == 9: opt_sets += "vampire," elif s == 10: opt_sets += "violent," for s in self._opt_set_checklist_list[1].GetCheckedItems(): if s == 0: opt_sets += "nemesis," elif s == 1: opt_sets += "will," elif s == 2: opt_sets += "shield," elif s == 3: opt_sets += "revenge," elif s == 4: opt_sets += "destroy," elif s == 5: opt_sets += "fight," elif s == 6: opt_sets += "determination," elif s == 7: opt_sets += "enhance," elif s == 8: opt_sets += "accuracy," elif s == 9: opt_sets += "tolerance," if len(opt_sets) > 0: opt_sets = opt_sets[:-1] command += (" --opt-sets " + opt_sets) command += (" --stats " + stats) command += (" --min-hp " + str(self._min_stat_slid_list[0].GetValue())) command += (" --min-atk " + str(self._min_stat_slid_list[1].GetValue())) command += (" --min-def " + str(self._min_stat_slid_list[2].GetValue())) command += (" --min-spd " + str(self._min_stat_slid_list[3].GetValue())) command += (" --min-crr " + str(self._min_stat_slid_list[4].GetValue())) command += (" --min-crd " + str(self._min_stat_slid_list[5].GetValue())) command += (" --min-res " + str(self._min_stat_slid_list[6].GetValue())) command += (" --min-acc " + str(self._min_stat_slid_list[7].GetValue())) command += (" --min-ehp " + str(self._min_stat_slid_list[8].GetValue())) command += (" --min-dmg " + str(self._min_stat_slid_list[9].GetValue())) if self._inventory_check.GetValue(): command += " --storage" if self._broken_check.GetValue(): command += " --broken" command += " --threads " + str(self._thread_slider.GetValue()) if len(self._teams_check_list.GetCheckedItems()) > 0: command += " --no-teams " for team in self._teams_check_list.GetCheckedItems(): command += str(self._team_ids[team]) + "," command = command[:-1] command += (" --gui ") print("Command: " + command) self._progress_gauge.SetValue(0) # Timer ot periodically check on the process self._timer = wx.Timer(self) self._timer.Start(1000) self.Bind(wx.EVT_TIMER, self._check_process) # Create and execute the process self.Bind(wx.EVT_END_PROCESS, self._optimization_complete) #print("Command: " + command) self._process = wx.Process(self) self._process.Redirect() wx.Execute(command, wx.EXEC_ASYNC, self._process) def _check_process(self, event): """ Checks the process output and updates progress bar. Parameters ---------- event : wxEvent, optional The event that triggered the call. """ if self._process is not None: stream = self._process.GetInputStream() if stream.CanRead(): text = bytes.decode(stream.read()) text = text[:-1] # Remove the last newline # Get only the last line if text.rfind("\n") != -1: text = text[text.rfind("\n") + 1:] # If the line is just a number, it's a progress indicator (1-20) if text.isnumeric() and int(text) <= 20: self._progress_gauge.SetValue(int(text)) else: self._timer.Stop() def _optimization_complete(self, event): """Called when the update process is complete. Hiddes the progress image, checks for errors in the output, prints a message annd sets self.updateDone and self.updateError. Parameters ---------- event : wxEvent, optional The event that triggered the call. """ self._timer.Stop() self._progress_gauge.SetValue(20) stream = self._process.GetInputStream() json_text = "" if stream.CanRead(): text = bytes.decode(stream.read()) text = text[:-1] # Remove the last newline # Get only the last line if text.rfind("\n") != -1: text = text[text.rfind("\n") + 1:] json_text = text print("---- RESULT OUTPUT -------------------------------------------") print(json_text) print("--------------------------------------------------------------") if json_text != "": data = json.loads( json_text, object_hook=lambda d: SimpleNamespace(**d) ) if data.result_count == 0: wx.MessageBox( parent=self, message="No results found for the current settings.", caption="No results found" ) else: self.GetParent().panel_results.process_results( unit_id=self._selected_unit.id, json_data=json_text ) self.GetParent().ChangeSelection(3) else: wx.MessageBox( parent=self, message="No data received from RuneOptimizer.", caption="Error" ) def _min_stat_change_by_slider(self, event=None): """ Changes text when a slider is changed. Doesn't do validation. Parameters ---------- event : wxEvent, optional The event that triggered the call (default is None). """ slid_id = int(event.GetEventObject().GetName().replace("slid", "")) self._min_stat_text_list[slid_id].SetValue( str(event.GetEventObject().GetValue()) ) def _min_stat_change_by_text(self, event=None): """ Changes the slider when the text is changed. Validates the text value. Parameters ---------- event : wxEvent, optional The event that triggered the call (default is None). """ text_id = int(event.GetEventObject().GetName().replace("tx", "")) if event.GetEventObject().GetValue().isdigit() == False and \ event.GetEventObject().GetValue() != "": event.GetEventObject().SetValue( str(self._min_stat_slid_list[text_id].GetValue()) ) min_value = self._min_stat_slid_list[text_id].GetMin() if event.GetEventObject().GetValue().isdigit(): value = int(event.GetEventObject().GetValue()) else: value = min_value # Unbind scroll event of the slider, set value and rebind. self._min_stat_slid_list[text_id].Unbind(wx.EVT_SCROLL) self._min_stat_slid_list[text_id].SetValue(value) self._min_stat_slid_list[text_id].Bind( wx.EVT_SCROLL, self._min_stat_change_by_slider ) def _adapt_stats(self, event=None): """ Sets all stats requeriments to the unit current values. Parameters ---------- event : wxEvent, optional The event that triggered the call (default is None). """ for i in range(0, 10): self._min_stat_slid_list[i].SetValue(self.unitStats[i]) self._min_stat_text_list[i].SetValue( str(self._min_stat_slid_list[i].GetValue()) ) def _reset_stats(self, event=None): """ Sets all stats requeriments to the unit base values. Parameters ---------- event : wxEvent, optional The event that triggered the call (default is None). """ for i in range(0, 10): self._min_stat_slid_list[i].SetValue( self._min_stat_slid_list[i].GetMin() ) self._min_stat_text_list[i].SetValue( str(self._min_stat_slid_list[i].GetMin()) )