|
|
@@ -0,0 +1,1329 @@
|
|
|
+"""
|
|
|
+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 <https://www.gnu.org/licenses/>.
|
|
|
+
|
|
|
+"""
|
|
|
+
|
|
|
+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())
|
|
|
+ )
|