// SPDX-FileCopyrightText: 2024 Kapdap <kapdap@pm.me> // // SPDX-License-Identifier: MIT /* CONSCRIPT Auto Splitter * https://github.com/kapdap/conscript-autosplitter * * Copyright 2024 Kapdap <kapdap@pm.me> * * Use of this source code is governed by an MIT-style * license that can be found in the LICENSE file or at * https://opensource.org/licenses/MIT. */ // Steam v1.0.1.2 state("CONSCRIPT", "v1.0.1.2 (S)") { int RoomId : "CONSCRIPT.exe", 0x1FB2750; double RESULTS_ACTIVE : "CONSCRIPT.exe", 0x21C5130, 0xB0, 0x320; double putteeSpeedModifier : "CONSCRIPT.exe", 0x21C5130, 0xB0, 0x1C0; long currentEnding : "CONSCRIPT.exe", 0x21C5130, 0xB0, 0x260; } // GOG v1.0.1.2 state("CONSCRIPT", "v1.0.1.2 (G)") { int RoomId : "CONSCRIPT.exe", 0x1B69538, 0x0, 0x18, 0x110; double RESULTS_ACTIVE : "CONSCRIPT.exe", 0x1B5A1C8, 0x30, 0x900, 0x50; double putteeSpeedModifier : "CONSCRIPT.exe", 0x1B5A1C8, 0x30, 0x5B0, 0x70; long currentEnding : "CONSCRIPT.exe", 0x1B5A1C8, 0x30, 0x540, 0x40; } // TODO: Epic Games release /*state("CONSCRIPT", "v1.0.0.0 (Epic)") { int RoomId : "CONSCRIPT.exe", 0xDBD0B8; double RESULTS_ACTIVE : "CONSCRIPT.exe", 0xBAD3F0, 0x30, 0x940, 0x40; }*/ init { // Based on GameMaker room name scanner by ero Func<IntPtr, IntPtr> onFound = addr => addr + 0x4 + game.ReadValue<int>(addr); var exe = modules.First(); var scn = new SignatureScanner(game, exe.BaseAddress, exe.ModuleMemorySize); if (exe.ModuleMemorySize == 0x2379000) version = "v1.0.1.2 (S)"; else if (exe.ModuleMemorySize == 0x1CCD000) version = "v1.0.1.2 (G)"; var roomArrayTrg = new SigScanTarget(5, "74 0C 48 8B 05 ???????? 48 8B 04 D0"); var roomArrLenTrg = new SigScanTarget(3, "48 3B 15 ???????? 73 ?? 48 8B 0D"); var arr = game.ReadPointer(onFound(scn.Scan(roomArrayTrg))); var len = game.ReadValue<int>(onFound(scn.Scan(roomArrLenTrg))); if (len == 0) throw new InvalidOperationException("Unable to read room array length."); vars.RoomNames = new string[len]; for (int i = 0; i < len; i++) { var name = game.ReadString(game.ReadPointer(arr + 0x8 * i), ReadStringType.UTF8, 64); vars.RoomNames[i] = name; } } start { return vars.RoomNames[current.RoomId] == "rm_tr_spawn" && current.RESULTS_ACTIVE == 1; } split { // Splits after going to bed at the end of the flashbacks if (vars.RoomNames[old.RoomId] == "rm_cs_bedroom" && vars.RoomNames[current.RoomId] == "rm_chapter_end") return true; // Splits after leaving in the truck at the end of chapter 5 flashback if (vars.RoomNames[old.RoomId] == "rm_cs_passage" && vars.RoomNames[current.RoomId] == "rm_text" && current.currentEnding != 6) // Don't split at the end of the secret ending return true; // End game split if (vars.RoomNames[old.RoomId] == "rm_ending_title" && vars.RoomNames[current.RoomId] == "rm_credits") return true; } update { current.Puttees = current.putteeSpeedModifier > 1 ? "Equipped" : "Unequipped"; current.RoomName = vars.RoomNames[current.RoomId]; } isLoading { return current.RESULTS_ACTIVE == 0; }