/****************************************************/
/* Metal Gear Solid Autosplitter 2.3 */
/* */
/* Emulator Compatibility: */
/* * BizHawk * DuckStation * ePSXe * Mednafen */
/* * Retroarch (Beetle PSX) */
/* */
/* Game Compatibility: */
/* * Metal Gear Solid (PSX EN/ES/US/JP) */
/* * Metal Gear Solid Integral (PSX JP) */
/* * Metal Gear Solid Integral (PC) */
/* * Metal Gear Solid Special Missions (PSX EN) */
/* * Metal Gear Solid VR Missions (PSX US) */
/* * Metal Gear Solid Integral VR-Disc (PSX JP) */
/* * Metal Gear Solid Integral VR-Disc (PC) */
/* */
/* Also compatible with MGS Master Collection */
/* for all supported games */
/* */
/* Created by bmn */
/* */
/* */
/* */
/* MGSR Clippy art modified from a piece by */
/* https://www.deviantart.com/nnmushroom */
/* */
/* Thanks to dlimes13, NickRPGreen and plywood_ */
/* for their feedback and suggestions */
/****************************************************/
/****************************************************/
/* state: Process names to attach to
/* If DuckStation's process name changes in the future, update it here
/* (it should continue to work as long as the name starts with "duckstation")
/****************************************************/
state("duckstation-qt-x64-ReleaseLTCG") {} // DuckStation
state("duckstation-nogui-x64-ReleaseLTCG") {} // DuckStation
state("ePSXe") {} // ePSXe
state("EmuHawk") {} // BizHawk
state("mednafen") {} // Mednafen
state("mgsi") {} // PC
state("mgsvr") {} // PC (VR Missions)
state("retroarch") {} // Retroarch (Beetle PSX only)
state("METAL GEAR SOLID") {} // Master Collection PC
/****************************************************/
/* startup: Initialise the autosplitter and define
/* all functions that don't need settings/current
/****************************************************/
startup {
vars.D = new ExpandoObject();
var D = vars.D;
// Create the main data structures the splitter will be using
D.Sets = new ExpandoObject(); // Sets of helper data
D.Names = new ExpandoObject(); // Sets of friendly names
D.Funcs = new ExpandoObject(); // Helper functions
D.Mem = new MemoryWatcherList(); // Active MemoryWatchers
D.ManualMem = new Dictionary(); // Manual MemoryWatcher (e.g. byte[])
D.New = new ExpandoObject(); // Functions to create new data structures
D.Game = new ExpandoObject(); // Data about the game/emulator
D.Run = new ExpandoObject(); // Splitter data about the run
D.Vars = new ExpandoObject(); // Splitter-specific variables
// Shortcuts for startup
var F = D.Funcs;
var V = D.Vars;
var New = D.New;
var G = D.Game;
var R = D.Run;
var M = D.Mem;
var MM = D.ManualMem;
// Initial Variable values
V.ExceptionCount = new Dictionary();
V.AllSettings = new HashSet();
V.DefaultSettings = new Dictionary();
V.DefaultParentSettings = new Dictionary();
V.DefaultSettingsTemplateCount = 0;
V.LiveSplitDir = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
V.AppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
+ "\\bmn\\MetalGearSolidAutosplitter";
V.DefaultSettingsFile = V.AppDataDir + "\\MetalGearSolid.DefaultSettings";
V.MajorSplitsFile = V.AppDataDir + "\\MetalGearSolid.MajorSplits";
V.DebugLogPath = V.AppDataDir + "\\MetalGearSolid.Autosplitter.log";
V.DebugLogBuffer = new List();
V.DebugForm = null;
V.TimerModel = new TimerModel { CurrentState = timer };
V.BaseFPS = refreshRate;
V.i = (int)0;
V.InitInitiated = false;
V.SplitFileDir = V.AppDataDir;
V.LastError = DateTime.Now;
// Initial Game values
G.BaseAddress = IntPtr.Zero;
G.OldBaseAddress = IntPtr.Zero;
G.ProductCode = String.Empty;
G.VRMissions = false;
G.FpsLog = new List< Tuple >();
G.Emulator = true;
G.Emulators = new List();
G.CurrentMemoryWatchers = new MemoryWatcherList();
G.HiddenMemoryWatchers = new MemoryWatcherList();
G.CodeMemoryWatchers = new MemoryWatcherList();
// Initial Run values
R.CompletedSplits = new Dictionary();
R.LatestSplits = new Stack();
R.ActiveWatchCodes = new HashSet();
R.CurrentLocations = new HashSet();
R.CurrentProgress = new HashSet();
R.AnyPercentRoute = false;
R.EscapeRadarTimes = 0;
R.VrSplitOnExit = false;
// Initialise structure for split watchers and checkers
F.Watch = new Dictionary>();
F.Check = new Dictionary>();
/****************************************************/
/* startup: Sets definitions
/****************************************************/
// Sets of progress values that can represent the same point in the game
// These names can be used in signatures (in place of progress) to cover multiple values
// Mostly used for PC where progress can change repeatedly hella fast
var progressSets = new Dictionary() {
// (value[n] == -1) -> next 2 are a progress range
{ "ReachDarpaChief", new short[] { -1, 19, 24 } },
{ "VentClip", new short[] { 18, 158 } },
{ "AfterOcelot", new short[] { -1, 52, 64 } },
{ "ReachNinja", new short[] { -1, 75, 77 } },
{ "ReachUgPassage", new short[] { -1, 141, 143 } },
{ "ABEscape", new short[] { 163 } },
{ "AfterEscape", new short[] { -1, 163, 173 } },
{ "DefeatCTAChase", new short[] { -1, 163, 174 } },
{ "CommTowerB", new short[] { -1, 180, 183, -1, 190, 195 } },
{ "BeforeHind", new short[] { -1, 180, 183 } },
{ "ReachHind", new short[] { 185, 186 } },
{ "AfterHind", new short[] { -1, 190, 194 } },
{ "ReachRaven", new short[] { -1, 207, 211 } },
{ "AfterRaven", new short[] { -1, 217, 219 } },
{ "ReachCommandRoom", new short[] { -1, 225, 237 } },
{ "HeatingKey", new short[] { -1, 242, 246 } },
};
D.Sets.Progress = new Dictionary>();
var pSet = D.Sets.Progress;
foreach (var p in progressSets) {
int count = p.Value.Length;
for (int i = 0; i < count; i++) {
var v = p.Value[i];
if (v == -1) {
for (short j = p.Value[i + 1]; j <= p.Value[i + 2]; j++) {
if (!pSet.ContainsKey(j)) pSet.Add(j, new List());
pSet[j].Add(p.Key);
}
i += 3;
}
if (!pSet.ContainsKey(v)) pSet.Add(v, new List());
pSet[v].Add(p.Key);
}
}
// Sets of locations, again for use in signatures
// Some are used as PC catch-alls (same as for progress)
// Others cover different ways to get to the same place (e.g. elevators with 3 floors)
var locationSets = new Dictionary() {
{ "Heliport", new string[] { "d00a", "s01a", "d01a" } },
{ "TankHangar", new string[] { "s02a", "s02c", "s02e", "s03a", "s04a" } },
{ "NukeBuilding", new string[] { "s06a", "s07a", "s08a" } },
{ "Snowfield", new string[] { "s12b", "s12c", "change" } },
};
D.Sets.Location = new Dictionary();
foreach (var l in locationSets) {
foreach (var m in l.Value) D.Sets.Location.Add(m, l.Key);
}
// Split modifiers { , }
// These are in the Split Modifiers section of settings
// If both and are enabled, 's split point will be disabled
// and will become an active split point
D.Sets.SplitModifiers = new Dictionary() {
{ "CP-7", "OL-s00a" },
{ "CP-153", "CP-157" },
{ "CP-163", "OL-s03c.CL-s03a.CP-163" },
{ "CP-178", "OL-s11g.CL-s11d" },
{ "CP-179", "OL-s11d.CL-s11i" },
};
// Memory addresses (relative to the start of PSX memory 0x000000 to 0x1FFFFF)
// for each PSX version of the game
D.Sets.PSXAddresses = new Dictionary>() {
// JP
{ "SLPM-86111", new Dictionary() {
{ "Alerts", 0xB581C },
{ "Kills", 0xB581E },
{ "RationsUsed", 0xB582C },
{ "Continues", 0xB582E },
{ "Saves", 0xB5830 },
{ "GameTime", 0xAC2D8 },
{ "Difficulty", 0xB577C },
{ "Progress", 0xB46BA },
{ "Location", 0xABCEC },
{ "NoControl", 0xABCF7 },
{ "InMenu", 0xAC806 },
{ "VsRex", 0xC0EB8 },
{ "ControllerInput", 0xAC240 },
{ "Frames", 0xABC58 },
{ "WeaponData", 0xB57A0 },
{ "ItemData", 0xB57CA },
{ "ElevatorTimer", 0x163B28 },
{ "OcelotHP", 0x167910 },
{ "NinjaHP", 0x15AC8C },
{ "MantisHP", 0x16C7A8 },
{ "Wolf1HP", 0x1747B4 },
{ "HindHP", 0x153FA8 },
{ "Wolf2HP", 0x171148 },
{ "RavenHP", 0x15779C },
{ "Rex1HP", 0x15E10C },
{ "Rex2HP", 0x15F414 },
{ "LiquidHP", 0x17A424 },
{ "LiquidPhase", 0x17A3F8 },
{ "EscapeHP", 0xB710E },
{ "RadarState", 0xABCF5 },
{ "O2Timer", 0xAC324 },
{ "ChaffTimer", 0xBE968 },
{ "DiazepamTimer", 0xB5812 },
{ "Life", 0xB5796 },
{ "MaxLife", 0xB5798 },
{ "EquippedItem", 0xB579E },
{ "ScoreHours", 0x11B084 },
} },
// JP Integral
{ "SLPM-86247", new Dictionary() {
{ "Alerts", 0xB4E34 },
{ "Kills", 0xB4E36 },
{ "RationsUsed", 0xB4E44 },
{ "Continues", 0xB4E46 },
{ "Saves", 0xB4E48 },
{ "GameTime", 0xAB9E8 },
{ "Difficulty", 0xB4D9A },
{ "Progress", 0xB3CD2 },
{ "Location", 0xAB3C4 },
{ "NoControl", 0xAB3CF },
{ "InMenu", 0xABDFC },
{ "VsRex", 0xC04F8 },
{ "ControllerInput", 0xAB950 },
{ "Frames", 0xAB330 },
{ "WeaponData", 0xB4DB8 },
{ "ItemData", 0xB4DE2 },
{ "ElevatorTimer", 0x1636D8 },
{ "OcelotHP", 0x1682DC },
{ "NinjaHP", 0x15BD30 },
{ "MantisHP", 0x16D280 },
{ "MantisMaxHP", 0xC3390 },
{ "Wolf1HP", 0x173484 },
{ "HindHP", 0x154E0C },
{ "Wolf2HP", 0x170204 },
{ "RavenHP", 0x157A1C },
{ "RavenMaxHP", 0xB40F0 },
{ "Rex1HP", 0x15E630 },
{ "RexMaxHP", 0xB40F6 },
{ "Rex2HP", 0x15F948 },
{ "LiquidHP", 0x179A54 },
{ "LiquidPhase", 0x179A28 },
{ "EscapeHP", 0xB6746 },
{ "RadarState", 0xAB3CD },
{ "O2Timer", 0xABA34 },
{ "ChaffTimer", 0xBDFA0 },
{ "DiazepamTimer", 0xB4E2A },
{ "Life", 0xB4DAE },
{ "MaxLife", 0xB4DB0 },
{ "EquippedItem", 0xB4DB6 },
{ "ScoreHours", 0x119434 },
} },
// JP VR
{ "SLPM-86249", new Dictionary() {
{ "Location", 0xA9018 },
{ "Score", 0xE2FC4 },
{ "LevelState", 0xE2FC8 },
{ "Frames", 0xA8F84 },
} },
// US 1.1
{ "SLUS-00594", new Dictionary() {
{ "Alerts", 0xB75B4 },
{ "Kills", 0xB75B6 },
{ "RationsUsed", 0xB75C4 },
{ "Continues", 0xB75C6 },
{ "Saves", 0xB75C8 },
{ "GameTime", 0xAE168 },
{ "Difficulty", 0xB751A },
{ "Progress", 0xB6452 },
{ "Location", 0xADB3C },
{ "NoControl", 0xADB47 },
{ "InMenu", 0xD2841 }, // maybe D2991, D2BD9, D2D89...
{ "VsRex", 0xC2C60 },
{ "ControllerInput", 0xAE0D0 },
{ "Frames", 0xADA50 },
{ "WeaponData", 0xB7538 },
{ "ItemData", 0xB7562 },
{ "ElevatorTimer", 0x162304 },
{ "OcelotHP", 0x168168 },
{ "NinjaHP", 0x15B59C },
{ "MantisHP", 0x16CFFC },
{ "MantisMaxHP", 0xC5AF0 },
{ "Wolf1HP", 0x173DEC },
{ "HindHP", 0x154CD4 },
{ "Wolf2HP", 0x1701BC },
{ "RavenHP", 0x157408 },
{ "RavenMaxHP", 0xB6970 },
{ "Rex1HP", 0x15E5A8 },
{ "RexMaxHP", 0xB6876 },
{ "Rex2HP", 0x15F8B0 },
{ "LiquidHP", 0x17997C },
{ "LiquidPhase", 0x179A28 },
{ "EscapeHP", 0xB8EAE },
{ "RadarState", 0xADB45 },
{ "O2Timer", 0xAE1B4 },
{ "ChaffTimer", 0xC0710 },
{ "DiazepamTimer", 0xB75AA },
{ "Life", 0xB752E },
{ "MaxLife", 0xB7530 },
{ "EquippedItem", 0xB7536 },
{ "ScoreHours", 0x11845C },
} },
// US 1.0
{ "SLUS-00594-1.0", new Dictionary() {
{ "Alerts", 0xB75AC },
{ "Kills", 0xB75AE },
{ "RationsUsed", 0xB75BC },
{ "Continues", 0xB75BE },
{ "Saves", 0xB75C0 },
{ "GameTime", 0xAE160 },
{ "Difficulty", 0xB7512 },
{ "Progress", 0xB644A },
{ "Location", 0xADB34 },
{ "NoControl", 0xADB3F },
{ "InMenu", 0xD2839 },
{ "VsRex", 0xC2C58 },
{ "ControllerInput", 0xAE0C8 },
{ "Frames", 0xADA48 },
{ "WeaponData", 0xB7530 },
{ "ItemData", 0xB755A },
{ "ElevatorTimer", 0x1622AC },
{ "OcelotHP", 0x168168 },
{ "NinjaHP", 0x15B6BC },
{ "MantisHP", 0x16CFEC },
{ "MantisMaxHP", 0xC5AE8 },
{ "Wolf1HP", 0x173DEC },
{ "HindHP", 0x154CD4 },
{ "Wolf2HP", 0x1701BC },
{ "RavenHP", 0x157408 },
{ "RavenMaxHP", 0xB6868 },
{ "Rex1HP", 0x15E5A8 },
{ "RexMaxHP", 0xB686E },
{ "Rex2HP", 0x15F8B0 },
{ "LiquidHP", 0x17997C },
{ "LiquidPhase", 0x179A50 },
{ "EscapeHP", 0xB8EAE },
{ "RadarState", 0xADB3D },
{ "O2Timer", 0xAE1AC },
{ "ChaffTimer", 0xC0708 },
{ "DiazepamTimer", 0xB75A2 },
{ "Life", 0xB7526 },
{ "MaxLife", 0xB7528 },
{ "EquippedItem", 0xB752E },
{ "ScoreHours", 0x11845C },
} },
// US VR
{ "SLUS-00957", new Dictionary() {
{ "Location", 0xAC1DC },
{ "Score", 0xB4A44 },
{ "LevelState", 0xB4A48 },
{ "Frames", 0xAC148 },
} },
// EU
{ "SLES-01370", new Dictionary() {
{ "Alerts", 0xB5E8C },
{ "Kills", 0xB5E8E },
{ "RationsUsed", 0xB5E9C },
{ "Continues", 0xB5E9E },
{ "Saves", 0xB5EA0 },
{ "GameTime", 0xACA40 },
{ "Difficulty", 0xB5DF2 },
{ "Progress", 0xB4D2A },
{ "Location", 0xAC430 },
{ "NoControl", 0xAC43B },
{ "InMenu", 0xD0F42 }, // todo test
{ "VsRex", 0xC1538 },
{ "ControllerInput", 0xAC9A8 },
{ "Frames", 0xAC39C },
{ "WeaponData", 0xB5E10 },
{ "ItemData", 0xB5E3A },
{ "ElevatorTimer", 0x1622F4 },
{ "OcelotHP", 0x168168 },
{ "NinjaHP", 0x15B6BC },
{ "MantisHP", 0x16D01C },
{ "MantisMaxHP", 0xC43D0 },
{ "Wolf1HP", 0x1737A8 },
{ "HindHP", 0x154CD4 },
{ "Wolf2HP", 0x1701BC },
{ "RavenHP", 0x157408 },
{ "RavenMaxHP", 0xB5148 },
{ "Rex1HP", 0x15E5A8 },
{ "RexMaxHP", 0xB514E },
{ "Rex2HP", 0x15F8B0 },
{ "LiquidHP", 0x17997C },
{ "LiquidPhase", 0x179950 },
{ "EscapeHP", 0xB778E },
{ "RadarState", 0xAC439 },
{ "O2Timer", 0xACA8C },
{ "ChaffTimer", 0xBEFE8 },
{ "DiazepamTimer", 0xB5E82 },
{ "Life", 0xB5E06 },
{ "MaxLife", 0xB5E08 },
{ "EquippedItem", 0xB5E0E },
{ "ScoreHours", 0x11845C },
} },
// EU VR
{ "SLES-02136", new Dictionary() {
{ "Location", 0xAC444 },
{ "Score", 0xB4CAC },
{ "LevelState", 0xB4CB0 },
{ "Frames", 0xAC3B0 },
} },
// Spain
{ "SLES-01734", new Dictionary() {
{ "Alerts", 0xB5FC4 },
{ "Kills", 0xB5FC6 },
{ "RationsUsed", 0xB5FD4 },
{ "Continues", 0xB5FD6 },
{ "Saves", 0xB5FD8 },
{ "GameTime", 0xACB78 },
{ "Difficulty", 0xB5F2A },
{ "Progress", 0xB4E62 },
{ "Location", 0xAC568 },
{ "NoControl", 0xAC573 },
{ "InMenu", 0xAD0A6 },
{ "VsRex", 0xC1670 },
{ "ControllerInput", 0xACAE0 }, // or ACAE4
{ "Frames", 0xAC4D4 },
{ "WeaponData", 0xB5F48 },
{ "ItemData", 0xB5F72 },
{ "ElevatorTimer", 0x1622F4 },
{ "OcelotHP", 0x167B78 },
{ "NinjaHP", 0x15BB8C },
{ "MantisHP", 0x16D020 },
{ "MantisMaxHP", 0xC4508 }, // or C4568
{ "Wolf1HP", 0x1737A8 },
{ "HindHP", 0x154CD4 },
{ "Wolf2HP", 0x1701BC },
{ "RavenHP", 0x157408 },
{ "RavenMaxHP", 0xB5280 },
{ "Rex1HP", 0x15FAB0 },
{ "RexMaxHP", 0xB5286 },
{ "Rex2HP", 0x15F8B0 },
{ "LiquidHP", 0x17997C },
{ "LiquidPhase", 0x179950 },
{ "EscapeHP", 0xB78C6 },
{ "RadarState", 0xAC571 },
{ "O2Timer", 0xACBC4 },
{ "ChaffTimer", 0xBF120 },
{ "DiazepamTimer", 0xB5FBA },
{ "Life", 0xB5F3E },
{ "MaxLife", 0xB5F40 },
{ "EquippedItem", 0xB5F46 },
{ "ScoreHours", 0x118480 },
} },
};
// Split set fragments - will be used later to create split sets
D.Sets.Split = new Dictionary>() {
{ "EarlyGame", new List() {
"OL-s00a", "OL-s01a.CL-s02a.CP-18", "OL-TankHangar.CL-s03a.CP-18",
} },
{ "Any", new List() {
"OL-s03a.CL-s03c.CP-VentClip", "OL-s03b.CL-s03c", "OL-s03c.CL-s03a.CP-163", "OL-TankHangar.CL-s04a.CP-163", "OL-TankHangar.CL-s02e.CP-163",
} },
{ "AllBosses", new List () {
"W.CL-s03a.CP-18", "CP-ReachDarpaChief", "OP-26", "OP-28", "CL-s04a.CP-36", "CL-s04b.CP-36", "OP-36", "OP-38", "OL-s04c.CL-s04a.CP-52", "OL-TankHangar.CL-s02c.CP-AfterOcelot", "CL-s05a.CP-AfterOcelot", "CP-65", "OP-66", "CL-s07a.CP-69", "CL-s08a.CP-69", "CL-s08c.CP-69", "CL-s08b.CP-ReachNinja", "OP-77", "OL-s08b.CL-s08c.CP-111", "OL-s08c.CL-s08a.CP-111", "CL-s07a.CP-111", "CP-112", "OL-s07c.CL-s07b.CP-119", "OP-125", "CP-133", "OL-s07b.CL-s09a.CP-137", "OL-s09a.CL-s10a.CP-ReachUgPassage", "CP-146", "OL-s10a.CL-s09a.CP-149", "OL-s09a.CL-s07b.CP-149", "OL-s07b.CL-s07a.CP-150", "OL-NukeBuilding.CL-s06a.CP-150", "OL-s06a.CL-s05a.CP-150", "OL-s05a.CL-s02e.CP-150", "OL-TankHangar.CL-s04a.CP-150", "OL-TankHangar.CL-s02e.CP-150", "OL-s02e.CL-s05a.CP-150", "OL-s05a.CL-s06a.CP-150", "OL-NukeBuilding.CL-s07a.CP-150", "OL-s07a.CL-s07b.CP-150", "OL-s07b.CL-s09a.CP-150", "OL-s09a.CL-s10a.CP-150", "OP-150", "CP-157", "OL-s03b.CL-s03c", "OL-s03c.CL-s03a.CP-163", "OL-TankHangar.CL-s02e.CP-ABEscape",
} },
{ "ToCommsTowers", new List() {
"OL-s02e.CL-s05a.CP-163", "OL-s05a.CL-s06a.CP-163", "OL-NukeBuilding.CL-s07a.CP-163", "OL-s07a.CL-s07b.CP-163", "OL-s07b.CL-s09a.CP-163", "OL-s09a.CL-s10a.CP-163", "OL-s10a.CL-s11a.CP-AfterEscape", "OL-s11a.CL-s11b.CP-DefeatCTAChase"
} },
{ "CommTowerA-Rappel", new List() {
"OL-s11g.CL-s11d", "OL-s11d.CL-s11i"
} },
{ "Walkway", new List() { "OL-s11i.CL-s11c.CP-180" } },
{ "CommTowerB-CAny", new List() {
"OL-s11c.CL-s11h.CP-BeforeHind", "OL-s11h.CL-s11c.CP-CommTowerB",
} },
{ "CommTowerB-AB", new List() {
"OL-s11c.CL-s11h.CP-BeforeHind", "CP-ReachHind", "OP-186", "OL-s11h.CL-s11c.CP-CommTowerB",
} },
{ "CommTowerB-Glitchless", new List() {
"OL-s11c.CL-s11e.CP-AfterHind", "CP-195"
} },
{ "ToWolf2", new List() {
"OL-s11c.CL-s12a.CP-CommTowerB", "CP-197", "OP-197",
} },
{ "Stinger-CAny", new List() {
"OL-Snowfield.CL-s11c.CP-204", "OL-s11c.CL-s11i.CP-204", "OL-s11i.CL-s11c.CP-204", "OL-s11c.CL-Snowfield.CP-204",
} },
{ "DiscChange", new List() { "OL-s12b.CL-change.CP-204" } },
{ "Disc2", new List() {
"OL-Snowfield.CL-s13a.CP-204", "OL-s13a.CL-s14e.CP-204", "CP-206", "CP-207", "OL-s14e.CL-s15a.CP-ReachRaven", "OP-211", "OL-s15a.CL-s15b.CP-AfterRaven", "OL-s15b.CL-s16a.CP-AfterRaven", "OL-s16a.CL-s16b.CP-221", "OL-s16b.CL-s16c.CP-223", "OL-s16c.CL-s16d.CP-ReachCommandRoom", "OL-s16d.CL-s16c.CP-ReachCommandRoom", "OL-s16c.CL-s16b.CP-237", "OL-s16b.CL-s16a.CP-237", "OL-s16a.CL-s16b.CP-238", "OL-s16b.CL-s16c.CP-238", "OL-s16c.CL-s16d.CP-238", "OP-238", "OL-s16d.CL-s16c.CP-240", "OL-s16c.CL-s16b.CP-240", "OL-s16b.CL-s16a.CP-240", "OL-s16a.CL-s15b.CP-240", "OL-s15b.CL-s15a.CP-240", "OL-s15a.CL-s15b.CP-240", "OL-s15b.CL-s16a.CP-240", "OL-s16a.CL-s16b.CP-240", "OL-s16b.CL-s16c.CP-240", "OL-s16c.CL-s16d.CP-240", "OP-240", "OL-s16d.CL-s16c.CP-242", "OL-s16c.CL-s16b.CP-242", "OL-s16b.CL-s16a.CP-242", "OL-s16a.CL-s15b.CP-242", "OL-s15b.CL-s15c.CP-242", "OL-s15c.CL-s14e.CP-242", "OL-s14e.CL-s13a.CP-HeatingKey", "OL-s13a.CL-s14e.CP-HeatingKey", "OL-s14e.CL-s15c.CP-HeatingKey", "OL-s15c.CL-s15b.CP-HeatingKey", "OL-s15b.CL-s16a.CP-HeatingKey", "OL-s16a.CL-s16b.CP-HeatingKey", "OL-s16b.CL-s16c.CP-HeatingKey", "OL-s16c.CL-s16d.CP-HeatingKey", "CP-247", "OL-s16d.CL-d16e", "CP-252", "W.CP-255", "W.CP-257", "OP-277", "OL-s19a.CL-s19b", "CP-286", "W.CP-294",
} },
};
D.Sets.AllSplits = new HashSet();
// Split sets for each category - uses the fragments above
// These are used when building split files from current settings
D.Sets.Category = new Dictionary>() {
{ "PC All Bosses", new List() {
"EarlyGame", "AllBosses", "ToCommsTowers", "CommTowerA-Rappel", "Walkway", "CommTowerB-AB", "ToWolf2", "Disc2"
} },
{ "Console All Bosses", new List() {
"EarlyGame", "AllBosses", "ToCommsTowers", "CommTowerA-Rappel", "Walkway", "CommTowerB-AB", "CommTowerB-Glitchless", "ToWolf2", "DiscChange", "Disc2"
} },
{ "PC Any%", new List() {
"EarlyGame", "Any", "ToCommsTowers", "CommTowerA-Rappel", "Walkway", "ToWolf2", "Disc2"
} },
{ "Console Any%", new List() {
"EarlyGame", "Any", "ToCommsTowers", "CommTowerA-Rappel", "Walkway", "CommTowerB-CAny", "ToWolf2", "DiscChange", "Stinger-CAny", "Disc2",
} },
{ "PC Glitchless", new List() {
"EarlyGame", "AllBosses", "ToCommsTowers", "CommTowerA-Rappel", "Walkway", "CommTowerB-AB", "CommTowerB-Glitchless", "ToWolf2", "Disc2"
} },
};
// How fast O2 drops in each area. 4096 is equivalent to 1/frame
D.Sets.O2Rates = new Dictionary() {
{ "s00a", 2048 },
{ "s02a", 8192 },
{ "s02c", 16384 }, // Technically you can backtrack to the rat poison, but for simplicity...
{ "s06a", 19200 },
{ "s08a", 3072 },
{ "s16a", 2048 },
{ "s16d", 8192 },
{ "s16d-ambush", 3000 },
};
// How much (as a divisor) the Gas Mask slows O2 loss
D.Sets.O2MaskDivisors = new Dictionary() {
{ "s00a", 8 },
{ "s02c", 8 },
{ "s06a", 16 },
{ "s08a", 4 },
{ "s16d", 2 },
};
// Difficulty names
D.Sets.Difficulties = new Dictionary() {
{ -1, "Very Easy" },
{ 0, "Easy" },
{ 1, "Normal" },
{ 2, "Hard" },
{ 3, "Extreme" },
};
/****************************************************/
/* startup: Friendly name definitions
/****************************************************/
// Split names - used when generating split files & when splitting in debug
D.Names.Split = new Dictionary() {
{ "OL-s00a", "Dock" },
{ "OL-s01a.CL-s02a.CP-18", "Heliport" },
{ "OL-TankHangar.CL-s03a.CP-18", "Tank Hangar" },
{ "OL-s03a.CL-s03c.CP-VentClip", "Cell" },
{ "M.OL-s03a.CL-s03c.CP-VentClip", "{Vent Clip}Cell" },
{ "W.CL-s03a.CP-18", "Cell" },
{ "CP-ReachDarpaChief", "DARPA Chief" },
{ "OP-26", "Cell" },
{ "OP-28", "Guard Encounter" },
{ "CL-s04a.CP-36", "Cell" },
{ "CL-s04b.CP-36", "Armory" },
{ "OP-36", "Armory South" },
{ "OP-38", "Revolver Ocelot" },
{ "OL-s04c.CL-s04a.CP-52", "Armory South" },
{ "OL-TankHangar.CL-s02c.CP-AfterOcelot", "Armory" },
{ "CL-s05a.CP-AfterOcelot", "Tank Hangar" },
{ "CP-65", "Canyon" },
{ "OP-66", "M1 Tank" },
{ "CL-s07a.CP-69", "Nuke Building 1F" },
{ "CL-s08a.CP-69", "Nuke Building B1" },
{ "CL-s08c.CP-69", "Nuke Building B2" },
{ "CL-s08b.CP-ReachNinja", "Lab Hallway" },
{ "OP-77", "Ninja" },
{ "OL-s08b.CL-s08c.CP-111", "Lab" },
{ "OL-s08c.CL-s08a.CP-111", "Lab Hallway" },
{ "CL-s07a.CP-111", "Nuke Building B2" },
{ "CP-112", "Meryl" },
{ "OL-s07c.CL-s07b.CP-119", "Nuke Building B1" },
{ "OP-125", "Commander's Room" },
{ "CP-133", "Psycho Mantis" },
{ "OL-s07b.CL-s09a.CP-137", "Commander's Room" },
{ "OL-s09a.CL-s10a.CP-ReachUgPassage", "Cave" },
{ "CP-146", "Underground Passage Ambush" },
{ "OL-s10a.CL-s09a.CP-149", "Underground Passage" },
{ "OL-s09a.CL-s07b.CP-149", "Cave" },
{ "OL-s07b.CL-s07a.CP-150", "Commander's Room" },
{ "OL-NukeBuilding.CL-s06a.CP-150", "Nuke Building B1" },
{ "OL-s06a.CL-s05a.CP-150", "Nuke Building 1F" },
{ "OL-s05a.CL-s02e.CP-150", "Canyon" },
{ "OL-TankHangar.CL-s04a.CP-150", "Tank Hangar" },
{ "OL-TankHangar.CL-s02e.CP-150", "Armory" },
{ "M.OL-TankHangar.CL-s02e.CP-150", "{PSG1}Armory" },
{ "OL-s02e.CL-s05a.CP-150", "Tank Hangar" },
{ "OL-s05a.CL-s06a.CP-150", "Canyon" },
{ "OL-NukeBuilding.CL-s07a.CP-150", "Nuke Building 1F" },
{ "OL-s07a.CL-s07b.CP-150", "Nuke Building B1" },
{ "OL-s07b.CL-s09a.CP-150", "Commander's Room" },
{ "OL-s09a.CL-s10a.CP-150", "Cave" },
{ "OP-150", "Sniper Wolf 1" },
{ "CP-157", "Underground Passage" },
{ "OL-s03b.CL-s03c", "Torture" },
{ "OL-s03c.CL-s03a.CP-163", "Medi Room" },
{ "M.OL-s03c.CL-s03a.CP-163", "{Escape}Medi Room" },
{ "OL-TankHangar.CL-s04a.CP-163", "Cell" }, // to Armory (Any%)
{ "OL-TankHangar.CL-s02e.CP-163", "Armory" },
{ "M.OL-TankHangar.CL-s02e.CP-163", "{PSG1}Armory" },
{ "OL-TankHangar.CL-s02e.CP-ABEscape", "Cell" }, // to Tank Hangar (AB)
{ "OL-s02e.CL-s05a.CP-163", "Tank Hangar" },
{ "OL-s05a.CL-s06a.CP-163", "Canyon" },
{ "OL-NukeBuilding.CL-s07a.CP-163", "Nuke Building 1F" },
{ "OL-s07a.CL-s07b.CP-163", "Nuke Building B1" },
{ "OL-s07b.CL-s09a.CP-163", "Commander's Room" },
{ "OL-s09a.CL-s10a.CP-163", "Cave" },
{ "OL-s10a.CL-s11a.CP-AfterEscape", "Underground Passage" },
{ "OL-s11a.CL-s11b.CP-DefeatCTAChase", "Comms Tower A" },
{ "M.OL-s11a.CL-s11b.CP-DefeatCTAChase", "{Stairs Chase}Comms Tower A" },
{ "OL-s11g.CL-s11d", "Comms Tower A Roof" },
{ "OL-s11d.CL-s11i", "Comms Tower A Wall" },
{ "M.OL-s11d.CL-s11i", "Rappel" },
{ "OL-s11i.CL-s11c.CP-180", "Walkway" },
{ "OL-s11c.CL-s11h.CP-BeforeHind", "Comms Tower B" }, // (AB/Console Any%)
{ "CP-ReachHind", "Comms Tower B Roof" }, // to Hind (AB)
{ "OP-186", "Hind D" },
{ "OL-s11h.CL-s11c.CP-CommTowerB", "Comms Tower B Roof" }, // back (AB/Console Any%)
{ "OL-s11c.CL-s11e.CP-AfterHind", "Comms Tower B" }, // to elevator (Console AB)
{ "CP-195", "Guard Encounter" }, // (Console AB)
{ "OL-s11c.CL-s12a.CP-CommTowerB", "Comms Tower B" },
{ "CP-197", "Snowfield" },
{ "OP-197", "Sniper Wolf 2" },
{ "OL-Snowfield.CL-s11c.CP-204", "Snowfield" }, // to CTB (Console Any%)
{ "OL-s11c.CL-s11i.CP-204", "Comms Tower B" },
{ "OL-s11i.CL-s11c.CP-204", "Walkway" },
{ "OL-s11c.CL-Snowfield.CP-204", "Comms Tower B" },
{ "OL-s12b.CL-change.CP-204", "Disc Change" }, // Console only
{ "OL-Snowfield.CL-s13a.CP-204", "Snowfield" },
{ "OL-s13a.CL-s14e.CP-204", "Blast Furnace" },
{ "CP-206", "Cargo Elevator" },
{ "CP-207", "Guard Encounter" },
{ "OL-s14e.CL-s15a.CP-ReachRaven", "Cargo Elevator" },
{ "OP-211", "Vulcan Raven" },
{ "OL-s15a.CL-s15b.CP-AfterRaven", "Warehouse" },
{ "OL-s15b.CL-s16a.CP-AfterRaven", "Warehouse North" },
{ "OL-s16a.CL-s16b.CP-221", "Underground Base 1" },
{ "OL-s16b.CL-s16c.CP-223", "Underground Base 2" },
{ "OL-s16c.CL-s16d.CP-ReachCommandRoom", "Underground Base 3" },
{ "OL-s16d.CL-s16c.CP-ReachCommandRoom", "Command Room" },
{ "OL-s16c.CL-s16b.CP-237", "Underground Base 3" },
{ "OL-s16b.CL-s16a.CP-237", "Underground Base 2" },
{ "OL-s16a.CL-s16b.CP-238", "Underground Base 1" },
{ "M.OL-s16a.CL-s16b.CP-238", "{PAL Key}Underground Base 1" },
{ "OL-s16b.CL-s16c.CP-238", "Underground Base 2" },
{ "OL-s16c.CL-s16d.CP-238", "Underground Base 3" },
{ "OP-238", "Normal PAL Key" },
{ "OL-s16d.CL-s16c.CP-240", "Command Room" },
{ "M.OL-s16d.CL-s16c.CP-240", "{Normal PAL Key}Command Room" },
{ "OL-s16c.CL-s16b.CP-240", "Underground Base 3" },
{ "OL-s16b.CL-s16a.CP-240", "Underground Base 2" },
{ "OL-s16a.CL-s15b.CP-240", "Underground Base 1" },
{ "OL-s15b.CL-s15a.CP-240", "Warehouse North" },
{ "M.OL-s15b.CL-s15a.CP-240", "{Enter Warehouse}Warehouse North" },
{ "OL-s15a.CL-s15b.CP-240", "Warehouse" },
{ "OL-s15b.CL-s16a.CP-240", "Warehouse North" },
{ "OL-s16a.CL-s16b.CP-240", "Underground Base 1" },
{ "OL-s16b.CL-s16c.CP-240", "Underground Base 2" },
{ "OL-s16c.CL-s16d.CP-240", "Underground Base 3" },
{ "OP-240", "Cold PAL Key" },
{ "OL-s16d.CL-s16c.CP-242", "Command Room" },
{ "M.OL-s16d.CL-s16c.CP-242", "{Cold PAL Key}Command Room" },
{ "OL-s16c.CL-s16b.CP-242", "Underground Base 3" },
{ "OL-s16b.CL-s16a.CP-242", "Underground Base 2" },
{ "OL-s16a.CL-s15b.CP-242", "Underground Base 1" },
{ "OL-s15b.CL-s15c.CP-242", "Warehouse North" },
{ "OL-s15c.CL-s14e.CP-242", "Warehouse" },
{ "OL-s14e.CL-s13a.CP-HeatingKey", "Cargo Elevator" },
{ "M.OL-s14e.CL-s13a.CP-HeatingKey", "{Enter Blast Furnace}Cargo Elevator" },
{ "OL-s13a.CL-s14e.CP-HeatingKey", "Blast Furnace" },
{ "OL-s14e.CL-s15c.CP-HeatingKey", "Cargo Elevator" },
{ "OL-s15c.CL-s15b.CP-HeatingKey", "Warehouse" },
{ "OL-s15b.CL-s16a.CP-HeatingKey", "Warehouse North" },
{ "OL-s16a.CL-s16b.CP-HeatingKey", "Underground Base 1" },
{ "OL-s16b.CL-s16c.CP-HeatingKey", "Underground Base 2" },
{ "OL-s16c.CL-s16d.CP-HeatingKey", "Underground Base 3" },
{ "CP-247", "Hot PAL Key" },
{ "OL-s16d.CL-d16e", "Command Room" },
{ "M.OL-s16d.CL-d16e", "{Hot PAL Key}Command Room" },
{ "CP-252", "Underground Base 3" },
{ "W.CP-255", "Metal Gear REX (Phase 1)" },
{ "W.CP-257", "Metal Gear REX" },
{ "OP-277", "Liquid Snake" },
{ "OL-s19a.CL-s19b", "Escape Route 1" },
{ "CP-286", "Escape" },
{ "M.CP-286", "{Escape}Escape Route 2" },
{ "W.CP-294", "Score" },
};
D.Names.SplitSetting = new Dictionary();
// Names of PSX versions of the game according to product code
D.Names.PSXVersion = new Dictionary() {
{ "SLPM-86111", "Metal Gear Solid (JP)" },
{ "SLPM-86247", "MGS Integral (JP)" },
{ "SLPM-86249", "MGS Integral VR-Disc (JP)" },
{ "SLUS-00594-1.0", "Metal Gear Solid (US 1.0)" },
{ "SLUS-00594", "Metal Gear Solid (US 1.1)" },
{ "SLUS-00957", "MGS VR Missions (US)" },
{ "SLES-01370", "Metal Gear Solid (Eur-EN)" },
{ "SLES-02136", "MGS Special Missions (Eur-EN)" },
{ "SLES-01734", "Metal Gear Solid (Eur-ES)" },
};
// Location names for [vars.Location] according to the Location memory value
// First character [sd] not included, last character only used when it varies
D.Names.Location = new Dictionary() {
{ "00", "Dock" },
{ "01", "Heliport" },
{ "02", "Tank Hangar" },
{ "03a", "Cell" },
{ "03b", "Medi Room" },
{ "03c", "Medi Room" },
{ "03d", "Cell" },
{ "04a", "Armory" },
{ "04b", "Armory South" },
{ "04c", "Armory South" },
{ "05", "Canyon" },
{ "06", "Nuke Building 1F" },
{ "07a", "Nuke Building B1"},
{ "07b", "Commander's Room" },
{ "07c", "Nuke Building B1"},
{ "08a", "Nuke Building B2" },
{ "08b", "Lab" },
{ "08c", "Lab Hallway" },
{ "09", "Cave" },
{ "10", "Underground Passage" },
{ "11a", "Comms Tower A" },
{ "11b", "Comms Tower A Roof" },
{ "11c", "Comms Tower B" },
{ "11d", "Comms Tower A Wall" },
{ "11e", "Comms Tower B Elevator" },
{ "11g", "Comms Tower A Roof" },
{ "11h", "Comms Tower B Roof" },
{ "11i", "Walkway" },
{ "12", "Snowfield" },
{ "13", "Blast Furnace" },
{ "14", "Cargo Elevator" },
{ "15a", "Warehouse" },
{ "15b", "Warehouse North" },
{ "15c", "Warehouse" },
{ "16a", "Underground Base 1" },
{ "16b", "Underground Base 2" },
{ "16c", "Underground Base 3" },
{ "16d", "Command Room" },
{ "16e", "Underground Base 3" },
{ "17", "Supply Route" },
{ "18", "Supply Route" },
{ "19a", "Escape Route 1" },
{ "19b", "Escape Route 2" },
};
// Weapon names - used in debug when checkers require a weapon
D.Names.Weapon = new Dictionary() {
{ 0, "" },
{ 1, "SOCOM" },
{ 2, "FA-MAS" },
{ 3, "Grenade" },
{ 4, "Nikita" },
{ 5, "Stinger" },
{ 6, "Claymore" },
{ 7, "C4" },
{ 8, "Stun Grenade" },
{ 9, "Chaff Grenade" },
{ 10, "PSG-1" },
};
// Item names - used in debug when checkers require an item
D.Names.Item = new Dictionary() {
{ 0, "Cigs" },
{ 1, "Scope" },
{ 2, "Box A" },
{ 3, "Box B" },
{ 4, "Box C" },
{ 5, "NVG" },
{ 6, "Thermal Goggles" },
{ 7, "Gas Mask" },
{ 8, "Body Armor" },
{ 9, "Ketchup" },
{ 10, "Stealth" },
{ 11, "Bandana" },
{ 12, "Camera" },
{ 13, "Ration" },
{ 14, "Medicine" },
{ 15, "Diazepam" },
{ 16, "PAL Key" },
{ 17, "Card" },
{ 18, "Time Bomb" },
{ 19, "Mine Detector" },
{ 20, "MO Disk" },
{ 21, "Rope" },
{ 22, "Handkerchief" },
{ 23, "Suppressor" },
};
/****************************************************/
/* startup: Helper function definitions
/****************************************************/
// Outputs to Windows stdout
// Replaced with a more capable version in init
F.Debug = (Action)((message) => {
print("[MGS1] " + message);
});
// Writes runtime errors to the error log (with a 5 sec cooldown)
// Replaced with a more capable version in init
F.EventLogWritten = new EntryWrittenEventHandler((Action