diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ab1b2e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.sublime-workspace diff --git a/Components/LiveSplit.Skyrim.dll b/Components/LiveSplit.Skyrim.dll index 9704c55..f2f3a8d 100644 Binary files a/Components/LiveSplit.Skyrim.dll and b/Components/LiveSplit.Skyrim.dll differ diff --git a/Components/update.LiveSplit.Skyrim.xml b/Components/update.LiveSplit.Skyrim.xml index 2e6296e..410739e 100644 --- a/Components/update.LiveSplit.Skyrim.xml +++ b/Components/update.LiveSplit.Skyrim.xml @@ -1,4 +1,14 @@ + + + + + + + Added automatic reset / start / end and Helgen split. + + + diff --git a/GameMemory.cs b/GameMemory.cs index 4dfad90..50b4fcd 100644 --- a/GameMemory.cs +++ b/GameMemory.cs @@ -10,24 +10,33 @@ namespace LiveSplit.Skyrim { class GameMemory { - // public event EventHandler OnFirstLevelLoading; - // public event EventHandler OnPlayerGainedControl; + public enum SplitArea : int + { + Helgen, + AlduinDefeated, + } + + public event EventHandler OnFirstLevelLoading; + public event EventHandler OnPlayerGainedControl; public event EventHandler OnLoadStarted; public event EventHandler OnLoadFinished; - public event EventHandler OnLoadScreenStarted; - public event EventHandler OnLoadScreenFinished; - public event EventHandler OnAlduinDefeated; + // public event EventHandler OnLoadScreenStarted; + // public event EventHandler OnLoadScreenFinished; + public delegate void SplitCompletedEventHandler(object sender, SplitArea type); + public event SplitCompletedEventHandler OnSplitCompleted; private Task _thread; private CancellationTokenSource _cancelSource; private SynchronizationContext _uiThread; private List _ignorePIDs; - // private DeepPointer _currentLevelPtr; private DeepPointer _isLoadingPtr; private DeepPointer _isLoadingScreenPtr; + private DeepPointer _isInLoadScreenFadeOutPtr; + private DeepPointer _isInTamriel; + private DeepPointer _world_XPtr; + private DeepPointer _world_YPtr; private DeepPointer _isAlduinDefeatedPtr; - // private int _stringBase; private enum ExpectedDllSizes { @@ -35,16 +44,26 @@ private enum ExpectedDllSizes SkyrimCracked = 26771456, } + private bool[] splitStates = new bool[(int)SplitArea.AlduinDefeated + 1]; + public GameMemory() { - _isLoadingPtr = new DeepPointer("TESV.exe", 0x17337CC); // == 1 if a loading is happening (any except loading screens in Helgen for some reason) + // Loads + _isLoadingPtr = new DeepPointer("TESV.exe", 0x17337CC); // == 1 if a load is happening (any except loading screens in Helgen for some reason) _isLoadingScreenPtr = new DeepPointer("TESV.exe", 0xEE3561); // == 1 if in a loading screen // _isPausedPtr = new DeepPointer("TESV.exe", 0x172E85F); // == 1 if in a menu or a loading screen + _isInLoadScreenFadeOutPtr = new DeepPointer("TESV.exe", 0x172EE2E); // == 1 from the fade out of a loading, it goes back to 0 once control is gained + + // Position + _isInTamriel = new DeepPointer("TESV.exe", 0x173815C); // == 1 if the player is in the Tamriel world space + _world_XPtr = new DeepPointer("TESV.exe", 0x0172E864, 0x64); // X world position (cell) + _world_YPtr = new DeepPointer("TESV.exe", 0x0172E864, 0x68); // Y world position (cell) - _isAlduinDefeatedPtr = new DeepPointer("TESV.exe", 0x12ACF78C); // == 1 when last blow is struck on alduin - // possible: 0x12ACF78C, 0x12FD23DB + // Game state + _isAlduinDefeatedPtr = new DeepPointer("TESV.exe", 0x1711608); // == 1 when last blow is struck on alduin + // _playerHasControlPtr = new DeepPointer("TESV.exe", 0x74814710); // == 1 when player has full control - // possible for start of splits: 13682838 == 18A4A + resetSplitStates(); _ignorePIDs = new List(); } @@ -52,9 +71,13 @@ public GameMemory() public void StartMonitoring() { if (_thread != null && _thread.Status == TaskStatus.Running) + { throw new InvalidOperationException(); + } if (!(SynchronizationContext.Current is WindowsFormsSynchronizationContext)) + { throw new InvalidOperationException("SynchronizationContext.Current is not a UI thread."); + } _uiThread = SynchronizationContext.Current; _cancelSource = new CancellationTokenSource(); @@ -64,12 +87,27 @@ public void StartMonitoring() public void Stop() { if (_cancelSource == null || _thread == null || _thread.Status != TaskStatus.Running) + { return; + } _cancelSource.Cancel(); _thread.Wait(); } + public void setSplitState(SplitArea split, bool value) + { + splitStates[(int)split] = value; + } + + public void resetSplitStates() + { + for (int i = 0; i <= (int)SplitArea.AlduinDefeated; i++) + { + splitStates[i] = false; + } + } + void MemoryReadThread() { Trace.WriteLine("[NoLoads] MemoryReadThread"); @@ -85,27 +123,25 @@ void MemoryReadThread() { Thread.Sleep(250); if (_cancelSource.IsCancellationRequested) + { return; + } } Trace.WriteLine("[NoLoads] Got TESV.exe!"); uint frameCounter = 0; - // int prevCurrentLevel = 0; bool prevIsLoading = false; bool prevIsLoadingScreen = false; bool prevIsAlduinDefeated = false; + bool prevIsInLoadScreenFadeOut = false; bool loadingStarted = false; bool loadingScreenStarted = false; while (!game.HasExited) { - // int currentLevel; - // _currentLevelPtr.Deref(game, out currentLevel); - // string currentLevelStr = GetEngineStringByID(game, currentLevel); - bool isLoading; _isLoadingPtr.Deref(game, out isLoading); @@ -113,23 +149,24 @@ void MemoryReadThread() _isLoadingScreenPtr.Deref(game, out isLoadingScreen); if (isLoadingScreen) + { isLoading = true; + } - bool isAlduinDefeated; - _isAlduinDefeatedPtr.Deref(game, out isAlduinDefeated); + bool isInLoadScreenFadeOut; + _isInLoadScreenFadeOutPtr.Deref(game, out isInLoadScreenFadeOut); + + bool isInTamriel; + _isInTamriel.Deref(game, out isInTamriel); - // if (currentLevel != prevCurrentLevel) - // { - // Trace.WriteLine(String.Format("{0} [NoLoads] Level Changed - {1} -> {2} '{3}'", frameCounter, prevCurrentLevel, currentLevel, currentLevelStr)); + int world_X; + _world_XPtr.Deref(game, out world_X); - // if (currentLevelStr == "l_tower_p" || currentLevelStr == "L_DLC07_BaseIntro_P" || currentLevelStr == "DLC06_Tower_P") - // { - // _uiThread.Post(d => { - // if (this.OnFirstLevelLoading != null) - // this.OnFirstLevelLoading(this, EventArgs.Empty); - // }, null); - // } - // } + int world_Y; + _world_YPtr.Deref(game, out world_Y); + + bool isAlduinDefeated; + _isAlduinDefeatedPtr.Deref(game, out isAlduinDefeated); if (isLoading != prevIsLoading) { @@ -139,9 +176,12 @@ void MemoryReadThread() loadingStarted = true; + // pause game timer _uiThread.Post(d => { if (this.OnLoadStarted != null) + { this.OnLoadStarted(this, EventArgs.Empty); + } }, null); } else @@ -152,9 +192,12 @@ void MemoryReadThread() { loadingStarted = false; + // unpause game timer _uiThread.Post(d => { if (this.OnLoadFinished != null) + { this.OnLoadFinished(this, EventArgs.Empty); + } }, null); } } @@ -168,11 +211,28 @@ void MemoryReadThread() loadingScreenStarted = true; - _uiThread.Post(d => + // nothing currently + // _uiThread.Post(d => + // { + // if (this.OnLoadScreenStarted != null) + // { + // this.OnLoadScreenStarted(this, EventArgs.Empty); + // } + // }, null); + + // if loadscreen starts while leaving helgen + if (!isInTamriel && world_X == -2 && world_Y == -5 && !splitStates[(int)SplitArea.Helgen]) { - if (this.OnLoadScreenStarted != null) - this.OnLoadScreenStarted(this, EventArgs.Empty); - }, null); + // Helgen split + Trace.WriteLine(String.Format("[NoLoads] Helgen Split - {0}", frameCounter)); + _uiThread.Post(d => + { + if (this.OnSplitCompleted != null) + { + this.OnSplitCompleted(this, SplitArea.Helgen); + } + }, null); + } } else { @@ -182,42 +242,72 @@ void MemoryReadThread() { loadingScreenStarted = false; - _uiThread.Post(d => - { - if (this.OnLoadScreenFinished != null) - this.OnLoadScreenFinished(this, EventArgs.Empty); - }, null); + // nothing currently + // _uiThread.Post(d => + // { + // if (this.OnLoadScreenFinished != null) + // { + // this.OnLoadScreenFinished(this, EventArgs.Empty); + // } + // }, null); } + } + } - // if (((currentMovie == "LoadingEmpressTower" || currentMovie == "INTRO_LOC") && currentLevelStr == "l_tower_p") - // || (currentMovie == "Loading" || currentMovie == "LoadingDLC06Tower") && currentLevelStr == "DLC06_Tower_P") // KoD - // { - // _uiThread.Post(d => { - // if (this.OnPlayerGainedControl != null) - // this.OnPlayerGainedControl(this, EventArgs.Empty); - // }, null); - // } + // if loadscreen fadeout finishes in helgen + if (isInLoadScreenFadeOut != prevIsInLoadScreenFadeOut && isInTamriel && world_X == 3 && world_Y == -20) + { + if (!isInLoadScreenFadeOut && prevIsInLoadScreenFadeOut) + { + // reset + Trace.WriteLine(String.Format("[NoLoads] Reset - {0}", frameCounter)); + _uiThread.Post(d => + { + if (this.OnFirstLevelLoading != null) + { + this.OnFirstLevelLoading(this, EventArgs.Empty); + } + }, null); + + // start + Trace.WriteLine(String.Format("[NoLoads] Start - {0}", frameCounter)); + _uiThread.Post(d => + { + if (this.OnPlayerGainedControl != null) + { + this.OnPlayerGainedControl(this, EventArgs.Empty); + } + }, null); } } - //if (isAlduinDefeated != prevIsAlduinDefeated && isAlduinDefeated) - //{ - // _uiThread.Post(d => { - // if (this.OnAlduinDefeated != null) - // this.OnAlduinDefeated(this, EventArgs.Empty); - // }, null); - //} + // if alduin is defeated in sovngarde + if (isAlduinDefeated != prevIsAlduinDefeated && isAlduinDefeated && !splitStates[(int)SplitArea.AlduinDefeated] + && !isInTamriel && ((world_X == 15 && world_Y == 19) || (world_X == 15 && world_Y == 20))) + { + // AlduinDefeated split + Trace.WriteLine(String.Format("[NoLoads] AlduinDefeated Split - {0}", frameCounter)); + _uiThread.Post(d => + { + if (this.OnSplitCompleted != null) + { + this.OnSplitCompleted(this, SplitArea.AlduinDefeated); + } + }, null); + } - // prevCurrentLevel = currentLevel; prevIsLoading = isLoading; prevIsLoadingScreen = isLoadingScreen; prevIsAlduinDefeated = isAlduinDefeated; + prevIsInLoadScreenFadeOut = isInLoadScreenFadeOut; frameCounter++; Thread.Sleep(15); if (_cancelSource.IsCancellationRequested) + { return; + } } } catch (Exception ex) @@ -233,25 +323,19 @@ Process GetGameProcess() Process game = Process.GetProcesses().FirstOrDefault(p => p.ProcessName.ToLower() == "tesv" && !p.HasExited && !_ignorePIDs.Contains(p.Id)); if (game == null) + { return null; + } if (game.MainModule.ModuleMemorySize != (int)ExpectedDllSizes.SkyrimSteam && game.MainModule.ModuleMemorySize != (int)ExpectedDllSizes.SkyrimCracked) { _ignorePIDs.Add(game.Id); _uiThread.Send(d => MessageBox.Show("Unexpected game version. Skyrim 1.9.32.0.8 is required.", "LiveSplit.Skyrim", - MessageBoxButtons.OK, MessageBoxIcon.Error), null); + MessageBoxButtons.OK, MessageBoxIcon.Error), null); return null; } return game; } - - // string GetEngineStringByID(Process p, int id) - // { - // string str; - // var ptr = new DeepPointer(_stringBase, (id*4), 0x10); - // ptr.Deref(p, out str, 32); - // return str; - // } } } diff --git a/LiveSplit.Skyrim.csproj b/LiveSplit.Skyrim.csproj index 5e2aa6b..4d9d295 100644 --- a/LiveSplit.Skyrim.csproj +++ b/LiveSplit.Skyrim.csproj @@ -66,14 +66,14 @@ - + - - + \ No newline at end of file diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 9bc85d3..b7869b1 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -33,7 +33,7 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.2.0.0")] -[assembly: AssemblyFileVersion("1.2.0.0")] +[assembly: AssemblyVersion("1.3.0.0")] +[assembly: AssemblyFileVersion("1.3.0.0")] [assembly: ComponentFactory(typeof(SkyrimFactory))] diff --git a/README.md b/README.md new file mode 100644 index 0000000..e1a98c6 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +LiveSplit.Skyrim v1.3 +===================== + +LiveSplit.Skyrim is a [LiveSplit](http://livesplit.org/) component for The Elder Scrolls V: Skyrim. + +Features +-------- + * Keeps track of Game Time to get rid of loading times. + * Auto start/stop/reset the timer. + * Splits when you finish Helgen and default Alduin 2. (configurable) + +Install +------- +Starting with LiveSplit 1.4, you can download and install LiveSplit.Skyrim automatically from within the Splits Editor with just one click. Just type in "The Elder Scrolls V: Skyrim" and click Activate. This downloads LiveSplit.Skyrim to the Components folder. + +Configure +--------- +Due to bugs in LiveSplit 1.4.0, it's recommended to deactivate LiveSplit.Skyrim in the Splits Editor after activating (downloading) it the first time. Instead, you should activate it in the Layout Editor, under the "Control" category. Double-click "Skyrim" after adding it to your layout to bring up the settings. + +After configuring everything you'll most likely want to turn on game time as primary timing, so that your splits will run off game time. You can do this by right-clicking LiveSplit and going to Compare Against->Game Time. + +#### Auto Split +The default settings are to automatically reset, start, and end the splits (the first and last splits). You can enable Helgen autosplitting here. + +#### Alternate Timing Method +This makes it show Real Time when comparing against Game Time, and vice versa. Doesn't work when LiveSplit.Skyrim is activated via the Splits Editor. + +Change Log +---------- +https://github.com/drtchops/LiveSplit.Skyrim/releases + +Credits +------- + * [DrTChops](http://twitch.tv/drtchops) + * [Dalleth](http://twitch.tv/dalleth_) + * Plugin is based off [LiveSplit.Dishonored](https://github.com/fatalis/LiveSplit.Dishonored) by [Fatalis](http://twitch.tv/fatalis_). diff --git a/SkyrimComponent.cs b/SkyrimComponent.cs index d664964..08f8172 100644 --- a/SkyrimComponent.cs +++ b/SkyrimComponent.cs @@ -37,26 +37,36 @@ public SkyrimComponent(LiveSplitState state) _state = state; _gameMemory = new GameMemory(); - // _gameMemory.OnFirstLevelLoading += gameMemory_OnFirstLevelLoading; - // _gameMemory.OnPlayerGainedControl += gameMemory_OnPlayerGainedControl; + _gameMemory.OnFirstLevelLoading += gameMemory_OnFirstLevelLoading; + _gameMemory.OnPlayerGainedControl += gameMemory_OnPlayerGainedControl; _gameMemory.OnLoadStarted += gameMemory_OnLoadStarted; _gameMemory.OnLoadFinished += gameMemory_OnLoadFinished; - _gameMemory.OnLoadScreenStarted += gameMemory_OnLoadScreenStarted; - _gameMemory.OnLoadScreenFinished += gameMemory_OnLoadScreenFinished; - _gameMemory.OnAlduinDefeated += gameMemory_OnAlduinDefeated; + // _gameMemory.OnLoadScreenStarted += gameMemory_OnLoadScreenStarted; + // _gameMemory.OnLoadScreenFinished += gameMemory_OnLoadScreenFinished; + _gameMemory.OnSplitCompleted += gameMemory_OnSplitCompleted; + state.OnReset += state_OnReset; _gameMemory.StartMonitoring(); } public void Dispose() { if (_gameMemory != null) + { _gameMemory.Stop(); + } + } + + void state_OnReset(object sender, TimerPhase e) + { + _gameMemory.resetSplitStates(); } public void Update(IInvalidator invalidator, LiveSplitState state, float width, float height, LayoutMode mode) { if (!this.Settings.DrawWithoutLoads) + { return; + } this.InternalComponent.TimeValue = state.CurrentTime[state.CurrentTimingMethod == TimingMethod.GameTime @@ -68,7 +78,9 @@ public void Update(IInvalidator invalidator, LiveSplitState state, float width, _cache["TimeValue"] = this.InternalComponent.ValueLabel.Text; _cache["TimingMethod"] = state.CurrentTimingMethod; if (invalidator != null && _cache.HasChanged) + { invalidator.Invalidate(0f, 0f, width, height); + } } public void DrawVertical(Graphics g, LiveSplitState state, float width, Region region) @@ -90,17 +102,21 @@ void PrepareDraw(LiveSplitState state) this.InternalComponent.NameLabel.HasShadow = this.InternalComponent.ValueLabel.HasShadow = state.LayoutSettings.DropShadows; } - // void gameMemory_OnFirstLevelLoading(object sender, EventArgs e) - // { - // if (this.Settings.AutoStartEnd) - // _timer.Reset(); - // } + void gameMemory_OnFirstLevelLoading(object sender, EventArgs e) + { + if (this.Settings.AutoStartEnd) + { + _timer.Reset(); + } + } - // void gameMemory_OnPlayerGainedControl(object sender, EventArgs e) - // { - // if (this.Settings.AutoStartEnd) - // _timer.Start(); - // } + void gameMemory_OnPlayerGainedControl(object sender, EventArgs e) + { + if (this.Settings.AutoStartEnd) + { + _timer.Start(); + } + } void gameMemory_OnLoadStarted(object sender, EventArgs e) { @@ -112,20 +128,24 @@ void gameMemory_OnLoadFinished(object sender, EventArgs e) _state.IsGameTimePaused = false; } - void gameMemory_OnLoadScreenStarted(object sender, EventArgs e) - { - // TODO - } + // void gameMemory_OnLoadScreenStarted(object sender, EventArgs e) + // { + // // Nothing to do + // } + + // void gameMemory_OnLoadScreenFinished(object sender, EventArgs e) + // { + // // Nothing to do + // } - void gameMemory_OnLoadScreenFinished(object sender, EventArgs e) + void gameMemory_OnSplitCompleted(object sender, GameMemory.SplitArea split) { - // TODO - } - - void gameMemory_OnAlduinDefeated(object sender, EventArgs e) - { - if (this.Settings.AutoStartEnd) - _timer.Split(); + if ((split == GameMemory.SplitArea.Helgen && this.Settings.Helgen) || + (split == GameMemory.SplitArea.AlduinDefeated && this.Settings.AutoStartEnd)) + { + _timer.Split(); + _gameMemory.setSplitState(split, true); + } } public XmlNode GetSettings(XmlDocument document) diff --git a/SkyrimSettings.Designer.cs b/SkyrimSettings.Designer.cs index 99bb884..ce5ed72 100644 --- a/SkyrimSettings.Designer.cs +++ b/SkyrimSettings.Designer.cs @@ -28,128 +28,140 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.tlpMain = new System.Windows.Forms.TableLayoutPanel(); - this.gbAutoSplit = new System.Windows.Forms.GroupBox(); - this.tlpAutoSplit = new System.Windows.Forms.TableLayoutPanel(); - this.chkAutoStartEnd = new System.Windows.Forms.CheckBox(); - this.gbLoadRemoval = new System.Windows.Forms.GroupBox(); - this.tlpLoadRemoval = new System.Windows.Forms.TableLayoutPanel(); - this.chkDisplayWithoutLoads = new System.Windows.Forms.CheckBox(); - this.tlpMain.SuspendLayout(); - this.gbAutoSplit.SuspendLayout(); - this.tlpAutoSplit.SuspendLayout(); - this.gbLoadRemoval.SuspendLayout(); - this.tlpLoadRemoval.SuspendLayout(); - this.SuspendLayout(); - // - // tlpMain - // - this.tlpMain.ColumnCount = 1; - this.tlpMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tlpMain.Controls.Add(this.gbAutoSplit, 1, 0); - this.tlpMain.Controls.Add(this.gbLoadRemoval, 0, 1); - this.tlpMain.Dock = System.Windows.Forms.DockStyle.Fill; - this.tlpMain.Location = new System.Drawing.Point(0, 0); - this.tlpMain.Name = "tlpMain"; - this.tlpMain.RowCount = 2; - this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 75F)); - this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); - this.tlpMain.Size = new System.Drawing.Size(476, 226); - this.tlpMain.TabIndex = 0; - // - // gbAutoSplit - // - this.gbAutoSplit.Controls.Add(this.tlpAutoSplit); - this.gbAutoSplit.Dock = System.Windows.Forms.DockStyle.Fill; - this.gbAutoSplit.Location = new System.Drawing.Point(3, 3); - this.gbAutoSplit.Name = "gbAutoSplit"; - this.gbAutoSplit.Size = new System.Drawing.Size(470, 163); - this.gbAutoSplit.TabIndex = 5; - this.gbAutoSplit.TabStop = false; - this.gbAutoSplit.Text = "Auto-Split"; - // - // tlpAutoSplit - // - this.tlpAutoSplit.ColumnCount = 1; - this.tlpAutoSplit.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tlpAutoSplit.Controls.Add(this.chkAutoStartEnd, 0, 0); - this.tlpAutoSplit.Dock = System.Windows.Forms.DockStyle.Fill; - this.tlpAutoSplit.Location = new System.Drawing.Point(3, 16); - this.tlpAutoSplit.Name = "tlpAutoSplit"; - this.tlpAutoSplit.RowCount = 6; - this.tlpAutoSplit.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tlpAutoSplit.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tlpAutoSplit.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tlpAutoSplit.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tlpAutoSplit.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tlpAutoSplit.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tlpAutoSplit.Size = new System.Drawing.Size(464, 44); - this.tlpAutoSplit.TabIndex = 0; - // - // chkAutoStartEnd - // - this.chkAutoStartEnd.AutoSize = true; - this.chkAutoStartEnd.Checked = true; - this.chkAutoStartEnd.CheckState = System.Windows.Forms.CheckState.Checked; - this.chkAutoStartEnd.Location = new System.Drawing.Point(3, 3); - this.chkAutoStartEnd.Name = "chkAutoStartEnd"; - this.chkAutoStartEnd.Size = new System.Drawing.Size(203, 17); - this.chkAutoStartEnd.TabIndex = 4; - this.chkAutoStartEnd.Text = "Start / Reset / End (Not yet working!)"; - this.chkAutoStartEnd.UseVisualStyleBackColor = true; - // - // gbLoadRemoval - // - this.gbLoadRemoval.Controls.Add(this.tlpLoadRemoval); - this.gbLoadRemoval.Dock = System.Windows.Forms.DockStyle.Fill; - this.gbLoadRemoval.Location = new System.Drawing.Point(3, 172); - this.gbLoadRemoval.Name = "gbLoadRemoval"; - this.gbLoadRemoval.Size = new System.Drawing.Size(470, 51); - this.gbLoadRemoval.TabIndex = 6; - this.gbLoadRemoval.TabStop = false; - this.gbLoadRemoval.Text = "Show Alternate Timing Time"; - // - // tlpLoadRemoval - // - this.tlpLoadRemoval.ColumnCount = 1; - this.tlpLoadRemoval.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tlpLoadRemoval.Controls.Add(this.chkDisplayWithoutLoads, 0, 0); - this.tlpLoadRemoval.Dock = System.Windows.Forms.DockStyle.Fill; - this.tlpLoadRemoval.Location = new System.Drawing.Point(3, 16); - this.tlpLoadRemoval.Name = "tlpLoadRemoval"; - this.tlpLoadRemoval.RowCount = 1; - this.tlpLoadRemoval.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tlpLoadRemoval.Size = new System.Drawing.Size(464, 32); - this.tlpLoadRemoval.TabIndex = 0; - // - // chkDisplayWithoutLoads - // - this.chkDisplayWithoutLoads.AutoSize = true; - this.chkDisplayWithoutLoads.Checked = true; - this.chkDisplayWithoutLoads.CheckState = System.Windows.Forms.CheckState.Checked; - this.chkDisplayWithoutLoads.Location = new System.Drawing.Point(3, 3); - this.chkDisplayWithoutLoads.Name = "chkDisplayWithoutLoads"; - this.chkDisplayWithoutLoads.Size = new System.Drawing.Size(59, 17); - this.chkDisplayWithoutLoads.TabIndex = 0; - this.chkDisplayWithoutLoads.Text = "Enable"; - this.chkDisplayWithoutLoads.UseVisualStyleBackColor = true; - // - // SkyrimSettings - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.tlpMain); - this.Name = "SkyrimSettings"; - this.Size = new System.Drawing.Size(476, 226); - this.tlpMain.ResumeLayout(false); - this.gbAutoSplit.ResumeLayout(false); - this.tlpAutoSplit.ResumeLayout(false); - this.tlpAutoSplit.PerformLayout(); - this.gbLoadRemoval.ResumeLayout(false); - this.tlpLoadRemoval.ResumeLayout(false); - this.tlpLoadRemoval.PerformLayout(); - this.ResumeLayout(false); - + this.tlpMain = new System.Windows.Forms.TableLayoutPanel(); + this.gbAutoSplit = new System.Windows.Forms.GroupBox(); + this.tlpAutoSplit = new System.Windows.Forms.TableLayoutPanel(); + this.chkAutoStartEnd = new System.Windows.Forms.CheckBox(); + this.gbLoadRemoval = new System.Windows.Forms.GroupBox(); + this.tlpLoadRemoval = new System.Windows.Forms.TableLayoutPanel(); + this.chkDisplayWithoutLoads = new System.Windows.Forms.CheckBox(); + this.chkHelgen = new System.Windows.Forms.CheckBox(); + this.tlpMain.SuspendLayout(); + this.gbAutoSplit.SuspendLayout(); + this.tlpAutoSplit.SuspendLayout(); + this.gbLoadRemoval.SuspendLayout(); + this.tlpLoadRemoval.SuspendLayout(); + this.SuspendLayout(); + // + // tlpMain + // + this.tlpMain.ColumnCount = 1; + this.tlpMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpMain.Controls.Add(this.gbAutoSplit, 1, 0); + this.tlpMain.Controls.Add(this.gbLoadRemoval, 0, 1); + this.tlpMain.Dock = System.Windows.Forms.DockStyle.Fill; + this.tlpMain.Location = new System.Drawing.Point(0, 0); + this.tlpMain.Name = "tlpMain"; + this.tlpMain.RowCount = 2; + this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 75F)); + this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tlpMain.Size = new System.Drawing.Size(476, 226); + this.tlpMain.TabIndex = 0; + // + // gbAutoSplit + // + this.gbAutoSplit.Controls.Add(this.tlpAutoSplit); + this.gbAutoSplit.Dock = System.Windows.Forms.DockStyle.Fill; + this.gbAutoSplit.Location = new System.Drawing.Point(3, 3); + this.gbAutoSplit.Name = "gbAutoSplit"; + this.gbAutoSplit.Size = new System.Drawing.Size(470, 163); + this.gbAutoSplit.TabIndex = 5; + this.gbAutoSplit.TabStop = false; + this.gbAutoSplit.Text = "Auto-Split"; + // + // tlpAutoSplit + // + this.tlpAutoSplit.ColumnCount = 1; + this.tlpAutoSplit.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpAutoSplit.Controls.Add(this.chkHelgen, 0, 5); + this.tlpAutoSplit.Controls.Add(this.chkAutoStartEnd, 0, 0); + this.tlpAutoSplit.Dock = System.Windows.Forms.DockStyle.Fill; + this.tlpAutoSplit.Location = new System.Drawing.Point(3, 16); + this.tlpAutoSplit.Name = "tlpAutoSplit"; + this.tlpAutoSplit.RowCount = 6; + this.tlpAutoSplit.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpAutoSplit.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpAutoSplit.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpAutoSplit.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpAutoSplit.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpAutoSplit.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpAutoSplit.Size = new System.Drawing.Size(464, 144); + this.tlpAutoSplit.TabIndex = 0; + // + // chkAutoStartEnd + // + this.chkAutoStartEnd.AutoSize = true; + this.chkAutoStartEnd.Checked = true; + this.chkAutoStartEnd.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkAutoStartEnd.Location = new System.Drawing.Point(3, 3); + this.chkAutoStartEnd.Name = "chkAutoStartEnd"; + this.chkAutoStartEnd.Size = new System.Drawing.Size(117, 17); + this.chkAutoStartEnd.TabIndex = 4; + this.chkAutoStartEnd.Text = "Start / Reset / End"; + this.chkAutoStartEnd.UseVisualStyleBackColor = true; + // + // gbLoadRemoval + // + this.gbLoadRemoval.Controls.Add(this.tlpLoadRemoval); + this.gbLoadRemoval.Dock = System.Windows.Forms.DockStyle.Fill; + this.gbLoadRemoval.Location = new System.Drawing.Point(3, 172); + this.gbLoadRemoval.Name = "gbLoadRemoval"; + this.gbLoadRemoval.Size = new System.Drawing.Size(470, 51); + this.gbLoadRemoval.TabIndex = 6; + this.gbLoadRemoval.TabStop = false; + this.gbLoadRemoval.Text = "Show Alternate Timing Time"; + // + // tlpLoadRemoval + // + this.tlpLoadRemoval.ColumnCount = 1; + this.tlpLoadRemoval.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpLoadRemoval.Controls.Add(this.chkDisplayWithoutLoads, 0, 0); + this.tlpLoadRemoval.Dock = System.Windows.Forms.DockStyle.Fill; + this.tlpLoadRemoval.Location = new System.Drawing.Point(3, 16); + this.tlpLoadRemoval.Name = "tlpLoadRemoval"; + this.tlpLoadRemoval.RowCount = 1; + this.tlpLoadRemoval.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpLoadRemoval.Size = new System.Drawing.Size(464, 32); + this.tlpLoadRemoval.TabIndex = 0; + // + // chkDisplayWithoutLoads + // + this.chkDisplayWithoutLoads.AutoSize = true; + this.chkDisplayWithoutLoads.Checked = true; + this.chkDisplayWithoutLoads.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkDisplayWithoutLoads.Location = new System.Drawing.Point(3, 3); + this.chkDisplayWithoutLoads.Name = "chkDisplayWithoutLoads"; + this.chkDisplayWithoutLoads.Size = new System.Drawing.Size(59, 17); + this.chkDisplayWithoutLoads.TabIndex = 0; + this.chkDisplayWithoutLoads.Text = "Enable"; + this.chkDisplayWithoutLoads.UseVisualStyleBackColor = true; + // + // chkHelgen + // + this.chkHelgen.AutoSize = true; + this.chkHelgen.Location = new System.Drawing.Point(3, 26); + this.chkHelgen.Name = "chkHelgen"; + this.chkHelgen.Size = new System.Drawing.Size(60, 17); + this.chkHelgen.TabIndex = 5; + this.chkHelgen.Text = "Helgen"; + this.chkHelgen.UseVisualStyleBackColor = true; + // + // SkyrimSettings + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tlpMain); + this.Name = "SkyrimSettings"; + this.Size = new System.Drawing.Size(476, 226); + this.tlpMain.ResumeLayout(false); + this.gbAutoSplit.ResumeLayout(false); + this.tlpAutoSplit.ResumeLayout(false); + this.tlpAutoSplit.PerformLayout(); + this.gbLoadRemoval.ResumeLayout(false); + this.tlpLoadRemoval.ResumeLayout(false); + this.tlpLoadRemoval.PerformLayout(); + this.ResumeLayout(false); + } #endregion @@ -161,5 +173,6 @@ private void InitializeComponent() private System.Windows.Forms.TableLayoutPanel tlpLoadRemoval; private System.Windows.Forms.TableLayoutPanel tlpAutoSplit; private System.Windows.Forms.CheckBox chkAutoStartEnd; + private System.Windows.Forms.CheckBox chkHelgen; } } diff --git a/SkyrimSettings.cs b/SkyrimSettings.cs index 6a2be9a..08e6048 100644 --- a/SkyrimSettings.cs +++ b/SkyrimSettings.cs @@ -9,6 +9,7 @@ public partial class SkyrimSettings : UserControl { public bool DrawWithoutLoads { get; set; } public bool AutoStartEnd { get; set; } + public bool Helgen { get; set; } public SkyrimSettings() { @@ -16,10 +17,12 @@ public SkyrimSettings() this.chkDisplayWithoutLoads.DataBindings.Add("Checked", this, "DrawWithoutLoads", false, DataSourceUpdateMode.OnPropertyChanged); this.chkAutoStartEnd.DataBindings.Add("Checked", this, "AutoStartEnd", false, DataSourceUpdateMode.OnPropertyChanged); + this.chkHelgen.DataBindings.Add("Checked", this, "Helgen", false, DataSourceUpdateMode.OnPropertyChanged); // defaults this.DrawWithoutLoads = true; this.AutoStartEnd = true; + this.Helgen = false; } public XmlNode GetSettings(XmlDocument doc) @@ -30,6 +33,7 @@ public XmlNode GetSettings(XmlDocument doc) settingsNode.AppendChild(ToElement(doc, "DrawWithoutLoads", this.DrawWithoutLoads)); settingsNode.AppendChild(ToElement(doc, "AutoStartEnd", this.AutoStartEnd)); + settingsNode.AppendChild(ToElement(doc, "Helgen", this.Helgen)); return settingsNode; } @@ -38,6 +42,7 @@ public void SetSettings(XmlNode settings) { this.DrawWithoutLoads = ParseBool(settings, "DrawWithoutLoads", true); this.AutoStartEnd = ParseBool(settings, "AutoStartEnd", true); + this.Helgen = ParseBool(settings, "Helgen", true); } static bool ParseBool(XmlNode settings, string setting, bool default_ = false) diff --git a/SkyrimSettings.resx b/SkyrimSettings.resx index 29dcb1b..58a9e20 100644 --- a/SkyrimSettings.resx +++ b/SkyrimSettings.resx @@ -1,120 +1,120 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/config/TESV.CT b/config/TESV.CT new file mode 100644 index 0000000..d0462fb --- /dev/null +++ b/config/TESV.CT @@ -0,0 +1,84 @@ + + + + + 0 + "isPaused" + + 80000008 + Byte +
"TESV.exe"+172E85F
+
+ + 1 + "isLoading" + + 80000008 + Byte +
"TESV.exe"+17337CC
+
+ + 3 + "isLoadscreen" + + 80000008 + Byte +
"TESV.exe"+EE3561
+
+ + 4 + "AreHandsTied?" + + 80000008 + Byte +
TESV.exe+172EE2C
+
+ + 5 + "IsInFadeOut" + + 80000008 + Byte +
TESV.exe+172EE2E
+
+ + 12 + "IsAlduinDead?" + + 80000008 + Byte +
TESV.exe+1711608
+
+ + 9 + "X world coord" + + 80000008 + 4 Bytes +
"TESV.exe"+0172E864
+ + 64 + +
+ + 11 + "Y world coord" + + 80000008 + 4 Bytes +
"TESV.exe"+0172E864
+ + 68 + +
+ + 18 + "isInTamriel" + + 80000008 + Byte +
TESV.exe+173815C
+
+
+ +
diff --git a/config/livesplit.skyrim.sublime-project b/config/livesplit.skyrim.sublime-project new file mode 100644 index 0000000..a9ec7d2 --- /dev/null +++ b/config/livesplit.skyrim.sublime-project @@ -0,0 +1,19 @@ +{ + "folders": + [ + { + "follow_symlinks": true, + "path": "../" + } + ], + "settings": + { + "tab_size": 4, + "rulers": [79], + "translate_tabs_to_spaces": true, + "ensure_newline_at_eof_on_save": true, + "trim_trailing_white_space_on_save": true, + "default_encoding": "UTF-8", + "default_line_ending": "unix" + } +} diff --git a/readme.txt b/readme.txt deleted file mode 100644 index 5404c57..0000000 --- a/readme.txt +++ /dev/null @@ -1,43 +0,0 @@ -This is a LiveSplit (livesplit.org) component for Skyrim. It removes load times -automatically and automates splitting. It is based on Fatalis' component for -Dishonored. - -Features: - - Frame-accurate load time removal. - - (Coming soon: Automatic reset, start, and split. Automatic splitting can - be done on mission end screens as well as at a few other common places.) - -Requirements: - - Skyrim (PC - latest) - LiveSplit 1.4+ - -Install: - - Drop the LiveSplit.Skyrim.dll into LiveSplit's Components directory. - Add Skyrim to your layout. - Switch to the no loads timer by going to Compare Against -> Game Time. - - (Soon: Enter "The Elder Scrolls V: Skyrim" in LiveSplit's splits editor. - Click activate.) - -Source Code: - - https://github.com/drtchops/LiveSplit.Skyrim - - -Plugin code credit goes to: -@fatalis_ -twitch.tv/fatalis_ -Fatalis @ irc2.speedrunslive.com IRC -fatalis.twitch@gmail.com - -With original Skyrim compatibility by: -Dalleth -twitch.tv/dalleth_ - -1.4 Update by: -DrTChops -twitch.tv/drtchops