state("TheOuterWorlds2-Win64-Shipping"){} startup { vars.Log = (Action)((output) => print("[The Outer Worlds 2 ASL] " + output)); vars.SetTextComponent = (Action)((id,text)=>{ var lsUI = typeof(LiveSplit.UI.Components.LayoutComponent).Namespace; var txtTypeName = "LiveSplit.UI.Components.TextComponent"; var asm = "LiveSplit.Text.dll"; var layout = timer.Layout; var tComps = layout.Components .Where(c => c.GetType().Name=="TextComponent") .Select(c => c.GetType().GetProperty("Settings").GetValue(c,null)); var s = tComps.FirstOrDefault(o => (string)o.GetType().GetProperty("Text1").GetValue(o,null)==id); if(s==null){ var tAsm = Assembly.LoadFrom("Components\\"+asm); var comp = Activator.CreateInstance(tAsm.GetType(txtTypeName),timer); layout.LayoutComponents.Add(new LiveSplit.UI.Components.LayoutComponent(asm,(LiveSplit.UI.Components.IComponent)comp)); s = comp.GetType().GetProperty("Settings").GetValue(comp,null); s.GetType().GetProperty("Text1").SetValue(s,id); } s.GetType().GetProperty("Text2").SetValue(s,text); }); timer.CurrentTimingMethod = TimingMethod.GameTime; vars.Transitions = new[] { new[] { "0101_JP", "0502_PlayerShip_P", "horizonPointSplit", "Split when leaving Horizon Point" }, new[] { "0203_Vox_P", "0201_PI_P", "voxStationSplit", "Split when leaving Vox Station" }, new[] { "0302int_Monastery_P", "0301_GR_P", "monasterySplit", "Split when leaving Alexandra Monastery" }, new[] { "0503_PeaceTalks_P", "0502_PlayerShip_P", "tranquilityStationSplit", "Split when leaving Tranqulity Station" }, new[] { "0604_Archive_P", "0601_CL_P", "archiveSplit", "Split when leaving The Archive" }, new[] { "0901_HP_P", "0905_SovereignsShip_P", "sovereignShipSplit", "Split when boarding the Sovereign's ship" } }; for (var i = 0; i < vars.Transitions.Length; i++) { var t = vars.Transitions[i]; settings.Add(t[2], true, t[3]); } settings.Add("endSlidesSplit", true, "Split when reaching end slides"); settings.Add("speedometer", false, "Show speed readout"); settings.Add("debugText", false, "[DEBUG] Show debug values"); } init { var scn = new SignatureScanner(game, game.MainModule.BaseAddress, game.MainModule.ModuleMemorySize); SigScanTarget.OnFoundCallback getRel = (p,s,ptr) => ptr + 4 + game.ReadValue(ptr); var gameEngineTrg = new SigScanTarget(8, "E8 ?? ?? ?? ?? 48 39 35 ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8B 0D") { OnFound = getRel }; vars.GameEnginePtr = scn.Scan(gameEngineTrg); var uWorldTrg = new SigScanTarget(3, "48 8B 05 ?? ?? ?? ?? 4C 8B C3 49 8B 08") { OnFound = getRel }; vars.UWorldPtr = scn.Scan(uWorldTrg); var syncLoadTrg = new SigScanTarget(5, "89 43 60 8B 05 ?? ?? ?? ??") { OnFound = getRel }; vars.SyncLoadCounterPtr = scn.Scan(syncLoadTrg); var fNamePoolTrg = new SigScanTarget(10, "40 38 3D ?? ?? ?? ?? 48 8D 15") { OnFound = getRel }; var fNamePool = scn.Scan(fNamePoolTrg); vars.FNameToString = (Func)(fName => { var number = (fName & 0xFFFFFFFF00000000) >> 0x20; var chunkIdx = (fName & 0x00000000FFFF0000) >> 0x10; var nameIdx = (fName & 0x000000000000FFFF) >> 0x00; var chunk = game.ReadPointer(fNamePool + 0x10 + (int)chunkIdx * 0x8); var nameEntry = chunk + (int)nameIdx * 0x2; var length = game.ReadValue(nameEntry) >> 6; var name = game.ReadString(nameEntry + 0x2, length); return number == 0 ? name : name + "_" + number; }); vars.Log("GameEngine Ptr: 0x"+vars.GameEnginePtr.ToString("X")); vars.Log("uWorld Ptr: 0x"+vars.UWorldPtr.ToString("X")); vars.Log("FNamePool Ptr: 0x"+fNamePool.ToString("X")); current.worldName = old.worldName = "None"; } update { IntPtr uWorld = game.ReadValue((IntPtr)vars.UWorldPtr); var worldFName = game.ReadValue(uWorld + 0x18); var worldName = vars.FNameToString(worldFName); current.worldName = (worldName == "None") ? old.worldName : worldName; var syncLoadCount = game.ReadValue((IntPtr)vars.SyncLoadCounterPtr); var flushLevelStreamingType = game.ReadValue((IntPtr)(uWorld + 0x920)); current.loading = (syncLoadCount != 0) || (flushLevelStreamingType != 0); // GameEngine.GameInstance.LocalPlayers[0].PlayerController.PlayerCharacter var playerCharacterPtr = new DeepPointer(vars.GameEnginePtr, 0x1178, 0x38, 0x0, 0x30, 0x378).Deref(game); var playerMovementPtr = game.ReadValue((IntPtr)(playerCharacterPtr + 0x3C0)); if(settings["speedometer"]) { var xVel = game.ReadValue((IntPtr)(playerMovementPtr + 0x130)); var yVel = game.ReadValue((IntPtr)(playerMovementPtr + 0x138)); var hVel = Math.Sqrt((xVel * xVel) + (yVel * yVel)) / 100; vars.SetTextComponent("Speed", hVel.ToString("0.00")); } if(settings["debugText"]) { vars.SetTextComponent("WorldName", current.worldName); vars.SetTextComponent("syncLoadCount", syncLoadCount.ToString()); vars.SetTextComponent("flushLevelStreaming", flushLevelStreamingType.ToString()); var sprinting = game.ReadValue((IntPtr)(playerMovementPtr + 0x1989)); vars.SetTextComponent("sprinting", sprinting.ToString()); var moving = game.ReadValue((IntPtr)(playerMovementPtr + 0x198B)); vars.SetTextComponent("moving", moving.ToString()); var isCrouched = (game.ReadValue((IntPtr)(playerCharacterPtr + 0x504)) & 1 )!= 0; vars.SetTextComponent("crouched", isCrouched.ToString()); var pressedJump = game.ReadValue((IntPtr)(playerCharacterPtr + 0x51C)); vars.SetTextComponent("jumpCount", pressedJump.ToString()); // GameEngine.GameInstance.SaveGameManager var saveGamePtr = new DeepPointer(vars.GameEnginePtr, 0x1178, 0x2D8).Deref(game); var interactionComponentPtr = game.ReadValue((IntPtr)(playerCharacterPtr + 0x1FC0)); var canInteract = game.ReadValue((IntPtr)(interactionComponentPtr + 0x230)); vars.SetTextComponent("canInteract", canInteract.ToString()); var interactTarget = game.ReadValue((IntPtr)(interactionComponentPtr + 0x260)); var targetDistance = game.ReadValue((IntPtr)(interactionComponentPtr + 0x24C)); vars.SetTextComponent("target", vars.FNameToString(game.ReadValue((IntPtr)(interactTarget + 0x18)))); vars.SetTextComponent("distance", targetDistance.ToString("0.00")); } } start { return (current.worldName == "0501_PS_Intro_P" && old.worldName == "CharacterCreation_Lite"); } split { // Only bother if world actually changed if (current.worldName != old.worldName) { for (var i = 0; i < vars.Transitions.Length; i++) { var t = vars.Transitions[i]; if (old.worldName == t[0] && current.worldName == t[1]) { if (settings[t[2]]) { return true; } } } if (old.worldName == "0905_SovereignsShip_P" && current.worldName == "09_endslides" && settings["endSlidesSplit"]) { return true; } } return false; } reset { return (current.worldName == "CharacterCreation_Lite" && old.worldName == "ConversationalMainMenu"); } onStart { timer.IsGameTimePaused = true; } isLoading { return current.loading; }