diff --git a/__version__.py b/__version__.py
new file mode 100644
index 0000000..6edee49
--- /dev/null
+++ b/__version__.py
@@ -0,0 +1,21 @@
+
+ProgramName = "Tomb Raider: Legend SCU"
+Version = "0.0.10.0"
+Copyright = "Copyright 2018 ANoDE85"
+Description = "Tomb Raider: Legend Startup Configuration Utility"
+ProjectSite = ("https://github.com/ANoDE85/PyTR7SCU", "Project Website")
+Contributers = [
+ "ANoDE85"
+]
+License = """This program 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.
+
+ This program 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 this program. If not, see ."""
\ No newline at end of file
diff --git a/gui/trl_scu_base.fbp b/gui/trl_scu_base.fbp
index 2d90dc3..194eb8e 100644
--- a/gui/trl_scu_base.fbp
+++ b/gui/trl_scu_base.fbp
@@ -1035,7 +1035,7 @@
-
+ OnSaveSettings
@@ -1123,7 +1123,95 @@
-
+ OnLoadSettings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gui/trl_scu_base.py b/gui/trl_scu_base.py
index abfb032..ec21409 100644
--- a/gui/trl_scu_base.py
+++ b/gui/trl_scu_base.py
@@ -116,6 +116,9 @@ def __init__( self, parent ):
self.m_load_btn = wx.Button( self, wx.ID_ANY, u"Load Settings", wx.DefaultPosition, wx.DefaultSize, 0 )
lower_button_sizer.Add( self.m_load_btn, 0, wx.ALL, 5 )
+ self.m_reset_btn = wx.Button( self, wx.ID_ANY, u"Reset", wx.DefaultPosition, wx.DefaultSize, 0 )
+ lower_button_sizer.Add( self.m_reset_btn, 0, wx.ALL, 5 )
+
lower_button_sizer.Add( ( 0, 0), 1, wx.EXPAND, 5 )
@@ -143,7 +146,11 @@ def __init__( self, parent ):
# Connect Events
self.m_level_choice.Bind( wx.EVT_CHOICE, self.OnSelectLevel )
self.m_exe_picker.Bind( wx.EVT_FILEPICKER_CHANGED, self.OnExeSelected )
+ self.m_save_btn.Bind( wx.EVT_BUTTON, self.OnSaveSettings )
+ self.m_load_btn.Bind( wx.EVT_BUTTON, self.OnLoadSettings )
+ self.m_reset_btn.Bind( wx.EVT_BUTTON, self.OnReset )
self.m_run_btn.Bind( wx.EVT_BUTTON, self.OnRun )
+ self.Bind( wx.EVT_MENU, self.OnAbout, id = self.m_mi_help_about.GetId() )
def __del__( self ):
pass
@@ -156,7 +163,19 @@ def OnSelectLevel( self, event ):
def OnExeSelected( self, event ):
event.Skip()
+ def OnSaveSettings( self, event ):
+ event.Skip()
+
+ def OnLoadSettings( self, event ):
+ event.Skip()
+
+ def OnReset( self, event ):
+ event.Skip()
+
def OnRun( self, event ):
event.Skip()
+ def OnAbout( self, event ):
+ event.Skip()
+
diff --git a/setup.py b/setup.py
index 07c8eca..d03a957 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,8 @@
import sys
from cx_Freeze import setup, Executable
+import __version__
+
# Dependencies are automatically detected, but it might need fine tuning.
build_exe_options = {"packages": ["os", "platform", "win32api"], "excludes": ["tkinter"]}
@@ -10,8 +12,8 @@
if sys.platform == "win32":
base = "Win32GUI"
-setup( name = "TR Legend SCU",
- version = "0.10",
- description = "TR Legend SCU",
+setup( name = __version__.ProgramName,
+ version = __version__.Version,
+ description = __version__.Description,
options = {"build_exe": build_exe_options},
executables = [Executable("trl_scu_main.py", base=base)])
\ No newline at end of file
diff --git a/trl_scu_main.py b/trl_scu_main.py
index 4f9f127..1c411bb 100644
--- a/trl_scu_main.py
+++ b/trl_scu_main.py
@@ -3,6 +3,7 @@
import subprocess
import traceback
import wx
+import wx.adv
have_winreg = False
try:
@@ -10,78 +11,80 @@
have_winreg = True
except:
pass
-
+
have_win32api = False
try:
from win32api import GetFileVersionInfo, LOWORD, HIWORD
have_win32api = True
except Exception as e:
pass
-
+
+import __version__
from gui.trl_scu_base import TrlScuMainFrame
-LevelChoices = {
- "Main Menu" : None,
-
- "Croft Manor": 1,
- "Croft Manor (3)" : 3,
- "Croft Manor (5)" : 5,
- "Croft Manor (11)" : 11,
- "Bolivia, Beginning" : 2,
- "Peru, Beginning" : 4,
- "Peru Past, Excavation Site" : 15,
- "Peru Present, Excavation Site" : 16,
- "Peru, Motorbike Chase" : 17,
- "Japan, Beginning" : 6,
- "Ghana, Beginning" : 7,
- "Ghana, Beginning" : 14,
+
+LevelChoices = (
+ (None, "Main Menu"),
+
+ (1, "Croft Manor"),
+ (2, "Bolivia - Tiwanaku"),
+ (3, "Croft Manor"),
+ (4, "Peru - Return to Paraiso"),
+ (15, "Peru - Excavation Site (Flashback)"),
+ (16, "Peru - Excavation Site (Present)"),
+ (17, "Peru - Motorbike Chase"),
+ (5, "Croft Manor"),
+ (6, "Japan"),
+ (7, "Ghana"),
+ (14, "Ghana"),
# 8 is unknown
- "Kazakhstan, Beginning" : 9,
- "Khazakhstan, Motorbike" : 18,
- "England, Beginning" : 10,
- "Nepal, Beginning" : 12,
- "Bolivia Redux, Beginning" : 13,
-}
-
-OutfitChoices = {
- "Default" : None,
-
- "Legend" : "lara",
- "Legend Union Jack": "lara_alt",
- "Legend Black":"lara_alta",
- "Legend Blue": "lara_altb",
- "Legend Pink": "lara_altc",
- "Biker": "lara_biker",
- "Biker Red": "lara_biker_alt",
- "Biker - No Jacket": "lara_biker_nj",
- "Bikini (white)": "lara_bikini",
- "Bikini (Black)": "lara_bikini_alt",
- "Catsuit": "lara_catsuit",
- "Snowsuit":"lara_catsuit_snow",
- "Classic Green":"lara_classic",
- "Classic White": "lara_classic_alt",
- "Evening Dress (Buggy outside of Japan level)":"lara_evening",
- "Evening Ripped": "lara_evening_alt",
- "Evening with Dragon Tatoo":"lara_evening_alta",
- "Evening Red": "lara_evening_red",
- "Goth": "lara_goth",
- "Goth Lace Shirt": "lara_goth_alt",
- "Special Forces":"lara_special_forces",
- "Special Forces Urban": "lara_special_forces_alt",
- "Sport": "lara_sport",
- "Sport Green":"lara_sport_alt",
- "Suit":"lara_suit",
- "Suit Cream": "lara_suit_alt",
- "Winter": "lara_winter",
- "Winter - No Jacket": "lara_winter_nj",
- "Winter Orange":"lara_winter_alt",
- "Winter Orange - No Jacket": "lara_winter_alt_nj",
- "Winter Pink": "lara_winter_alta",
- "Winter Pink - No Jacket": "lara_winter_alta_nj",
- "Young Lara (from Flashback)":"lara_young",
- "Amanda": "amanda_player",
- "Amanda Winter": "amanda_player_alt"
-}
+ (9, "Kazakhstan - Project Carbonek"),
+ (18, "Khazakhstan, Motorbike Chase"),
+ (10, "England - King Arthur's Tomb"),
+ (11, "Croft Manor"),
+ (12, "Nepal - The Ghalali Key"),
+ (13, "Bolivia Redux"),
+)
+
+OutfitChoices = (
+ (None, "Default"),
+
+ ("lara", "Legend" ),
+ ("lara_alt", "Legend Union Jack"),
+ ("lara_alta", "Legend Black"),
+ ("lara_altb", "Legend Blue"),
+ ("lara_altc", "Legend Pink"),
+ ("lara_biker", "Biker"),
+ ("lara_biker_alt", "Biker Red"),
+ ("lara_biker_nj", "Biker - No Jacket"),
+ ("lara_bikini", "Bikini (white)"),
+ ("lara_bikini_alt", "Bikini (Black)"),
+ ("lara_catsuit", "Catsuit"),
+ ("lara_catsuit_snow", "Snowsuit"),
+ ("lara_classic", "Classic Green"),
+ ("lara_classic_alt", "Classic White"),
+ ("lara_evening", "Evening Dress (Buggy outside of Japan level)"),
+ ("lara_evening_alt", "Evening Ripped"),
+ ("lara_evening_alta", "Evening with Dragon Tattoo"),
+ ("lara_evening_red", "Evening Red"),
+ ("lara_goth", "Goth"),
+ ("lara_goth_alt", "Goth Lace Shirt"),
+ ("lara_special_forces", "Special Forces"),
+ ("lara_special_forces_alt", "Special Forces Urban"),
+ ("lara_sport", "Sport"),
+ ("lara_sport_alt", "Sport Green"),
+ ("lara_suit", "Suit"),
+ ("lara_suit_alt", "Suit Cream"),
+ ("lara_winter", "Winter"),
+ ("lara_winter_nj", "Winter - No Jacket"),
+ ("lara_winter_alt", "Winter Orange"),
+ ("lara_winter_alt_nj", "Winter Orange - No Jacket"),
+ ("lara_winter_alta", "Winter Pink"),
+ ("lara_winter_alta_nj", "Winter Pink - No Jacket"),
+ ("lara_young", "Young Lara (from Flashback)"),
+ ("amanda_player", "Amanda"),
+ ("amanda_player_alt", "Amanda Winter"),
+)
AdvancedOptions = [
("-DRAWMONSTERATTACK", "Draw monster attack" , False),
@@ -102,23 +105,25 @@ class MainFrame(TrlScuMainFrame):
def __init__(self):
TrlScuMainFrame.__init__(self, None)
self.__m_current_outfit = None
+ self.__m_outfit_to_id_map = {}
self.__m_current_level = None
self.__m_current_adv_opts = {}
- self._m_outfit_boxes = []
- self._m_devopts_controls = {}
+ self.__m_outfit_boxes = []
+ self.__m_devopts_controls = {}
self._InitMainOptions()
self._InitAdvancedOptions()
self._FindLegend()
self.Fit()
def _InitMainOptions(self):
- for name, id in LevelChoices.items():
- self.m_level_choice.Append(name, id)
+ for id, name in LevelChoices:
+ item_name = ("%s (%d)" % (name, id)) if id is not None else name
+ self.m_level_choice.Append(item_name, id)
self.m_level_choice.Select(0)
-
-
+
+
is_first = True
- for name, id in OutfitChoices.items():
+ for id, name in OutfitChoices:
if is_first:
flags = wx.RB_GROUP
else:
@@ -126,12 +131,12 @@ def _InitMainOptions(self):
is_first = False
outfit_button = wx.RadioButton( self.m_outer_radio_sizer.GetStaticBox(), wx.ID_ANY, name, wx.DefaultPosition, wx.DefaultSize, flags )
outfit_button.Bind( wx.EVT_RADIOBUTTON, self.OnOutfitChoice)
- self._m_outfit_boxes.append(outfit_button)
+ self.__m_outfit_boxes.append(outfit_button)
+ self.__m_outfit_to_id_map[outfit_button.GetId()] = id
self.m_outfit_sizer.Add( outfit_button, 0, wx.ALL, 5 )
self.m_outer_radio_sizer.Layout()
-
+
def _InitAdvancedOptions(self):
- self._m_devopts_controls = {}
for (key, caption, has_parameter) in AdvancedOptions:
text_box = None
check_box = wx.CheckBox(self.m_outer_dev_opts_sizer.GetStaticBox(), wx.ID_ANY, caption, wx.DefaultPosition, wx.DefaultSize, 0, name=key)
@@ -144,10 +149,10 @@ def _InitAdvancedOptions(self):
self.m_inner_dev_opts_content_sizer.Add( text_box, 0, wx.ALL|wx.EXPAND, 5 )
else:
self.m_inner_dev_opts_content_sizer.Add( (0, 0), 0, wx.ALL, 5 )
- self._m_devopts_controls[key] = (check_box, text_box)
+ self.__m_devopts_controls[key] = (check_box, text_box)
self.m_outer_dev_opts_sizer.Layout()
-
- def _FindLegend(self):
+
+ def _FindLegend(self):
if not have_winreg:
return
try:
@@ -160,7 +165,7 @@ def _FindLegend(self):
"Could not auto-detect TR Legend:\n\n%s" % (str(e), ),
"Auto detection failed",
wx.ICON_WARNING)
-
+
def SetLegendExecutable(self, exe_path):
exe_path = os.path.abspath(exe_path)
self.m_exe_picker.SetPath(exe_path)
@@ -172,7 +177,7 @@ def SetLegendExecutable(self, exe_path):
exe_version_string,),
"Wrong game version", wx.ICON_WARNING)
self.m_version_display_text.SetValue(exe_version_string)
-
+
def GetExecutableVersion(self, filename):
if not have_win32api:
wx.MessageBox("No api")
@@ -184,31 +189,63 @@ def GetExecutableVersion(self, filename):
return HIWORD (ms), LOWORD (ms), HIWORD (ls), LOWORD (ls)
except:
return 0,0,0,0
-
+
def OnExeSelected(self, event):
self.SetLegendExecutable(event.GetPath())
-
+
def OnOutfitChoice(self, evt):
- self.__m_current_outfit = OutfitChoices[evt.GetEventObject().GetLabelText()]
-
+ self.__m_current_outfit = self.__m_outfit_to_id_map[evt.GetEventObject().GetId()]
+
def OnSelectLevel(self, event):
self.__m_current_level = self.m_level_choice.GetClientData(event.GetSelection())
def OnToggleAdvanced(self, event):
key = event.GetEventObject().GetName()
- (check_box, text_box) = self._m_devopts_controls[key]
+ (check_box, text_box) = self.__m_devopts_controls[key]
if text_box:
text_box.Enabled = check_box.IsChecked()
+
+ def OnSaveSettings(self, event):
+ self._WriteConfig()
+
+ def OnLoadSettings(self, event):
+ wx.MessageBox("Sorry, not implemented yet.")
+
+ def OnReset(self, event):
+ config_path = self._GetConfigFilePath()
+ if not os.path.exists(config_path):
+ return
+ res = wx.MessageBox("This will remove the file '%s' from your computer.\n\nDo you wish to continue?" % (config_path, ),
+ "Confirmation", wx.ICON_INFORMATION | wx.YES_NO)
+ if res != wx.YES:
+ return
+ try:
+ os.unlink(config_path)
+ except Exception as e:
+ wx.MessageBox("Error while removing '%s': %s" % (config_path, str(e)), "Warning", wx.ICON_ERROR)
+ def OnAbout(self, event):
+ info = wx.adv.AboutDialogInfo()
+ info.Name = __version__.ProgramName
+ info.Version = __version__.Version
+ info.Copyright = __version__.Copyright
+ info.Description = __version__.Description
+ info.WebSite = __version__.ProjectSite
+ info.Developers = __version__.Contributers
+ info.License = __version__.License
+ # Show the wx.AboutBox
+ wx.adv.AboutBox(info)
+
+
def _GetAdvancedOptions(self):
opts = []
- for key, (check_box, text_box) in self._m_devopts_controls.items():
+ for key, (check_box, text_box) in self.__m_devopts_controls.items():
if check_box.IsChecked():
opts.append(key)
if text_box:
opts.append('"%s"' % (text_box.GetValue(), ))
return opts
-
+
def _GetCommandLineOptions(self):
options = []
if self.__m_current_level:
@@ -218,40 +255,48 @@ def _GetCommandLineOptions(self):
options.extend(self._GetAdvancedOptions())
return options
- def _WriteConfig(self, legend_install_dir):
- config_dir = os.path.join(legend_install_dir, "TR7", "GAME", "PC")
+ def _GetConfigFilePath(self):
+ exe_path = self._GetTombRaiderExecutable()
+ if not exe_path:
+ raise Exception("Please set the Tomb Raider Legend executable path!");
+ legend_install_dir = os.path.dirname(exe_path)
+ return os.path.join(os.path.splitdrive(legend_install_dir)[0] + os.sep, "TR7", "GAME", "PC", "TR7.arg")
+
+ def _GetTombRaiderExecutable(self):
+ return self.m_exe_picker.GetPath()
+
+ def _WriteConfig(self):
+ command_line_args = self._GetCommandLineOptions()
+
+ config_file_path = self._GetConfigFilePath()
+ config_dir = os.path.dirname(config_file_path)
if not os.path.isdir(config_dir):
try:
os.makedirs(config_dir)
except Exception as e:
raise Exception("Could not create config directory '%s': %s",
(config_dir, str(e)))
- command_line_args = self._GetCommandLineOptions()
- config_file_path = os.path.join(config_dir, "TR7.arg")
with open(config_file_path, "w+") as config_file:
config_file.write(" ".join(command_line_args))
-
- def _LaunchGame(self, exe_path):
+
+ def _LaunchGame(self):
+ exe_path = self._GetTombRaiderExecutable()
+ if not os.path.isfile(exe_path):
+ raise Exception("Tomb Raider Legend executable was not found at '%s'!" % (exe_path, ))
+
p = subprocess.Popen(
- executable=exe_path,
+ executable=exe_path,
args=[],
cwd=os.path.dirname(exe_path))
- # p.wait()
-
+
def OnRun(self, event):
try:
- exe_path = self.m_exe_picker.GetPath()
- if not exe_path:
- raise Exception("Please set the Tomb Raider Legend executable path!");
- if not os.path.isfile(exe_path):
- raise Exception("Tomb Raider Legend executable was not found at '%s'!" % (exe_path, ))
- legend_install_dir = os.path.dirname(exe_path)
- self._WriteConfig(legend_install_dir)
- self._LaunchGame(exe_path)
+ self._WriteConfig()
+ self._LaunchGame()
except Exception as e:
wx.MessageBox("%s" % (e, ), "Error launching TR Legend", wx.ICON_ERROR)
traceback.print_exc()
-
+
class Application(wx.App):
@@ -260,7 +305,7 @@ def OnInit(self):
self.SetTopWindow(self._m_main_frame)
self._m_main_frame.Show()
return True
-
+
def Start(self):
self.MainLoop()