Skip to content
Beta: this is a preview of the new SplitScreen.Me. Data may be reset before launch.

OpenTTD · handler “OpenTTD”

Version 4

Release notes

removed interface size 75, it was not supported

Released
Size
3.2 KB
Downloads
12
Check
Verified
SHA-256
2e1a9e02f26f5399b38b53972160271d3fce8304aa45c8f205b89330ea9cb46c
Download v4 (.nc)All versions

Files 1

PathSize
handler.js13 KB

handler.js

Plain text
Hub.Handler.Version = 4; // Released at https://hub.splitscreen.me/ on Sun Oct 06 2024 18:26:41 GMT+0000 (Coordinated Universal Time).
Hub.Handler.Id = "MYutujfMT93Duiriz";
Hub.Maintainer.Name = "messenils";
Hub.Maintainer.Id = "5NNQPxAD7mmwGuvKp";

var answers1 = ["ONE", "ALL", "NONE"];
Game.AddOption("Music", "How many instances play music.", "Music", answers1);
var answers2 = ["60", "0", "10", "20", "30", "40", "50", "70", "80", "90", "100"];
Game.AddOption("Music Volume", "music volume.", "Volume", answers2);
var answers3 = ["100", "0", "10", "20", "30", "40", "50", "60", "70", "80", "90"];
Game.AddOption("Sound Volume", "sound volume.", "SFVolume", answers3);
var answers4 = ["No Change", "100", "125", "150", "175", "200", "225", "250", "275", "300", "325", "350", "375", "400"];
Game.AddOption("Interface size", "recommend from 150 to 300 depending on screen size", "Interface", answers4);
var answers5 = ["No", "Yes"];
Game.AddOption("Fast setup", "Starts games in correct position. Report if you experience problems with this option", "Initpos", answers5);

Game.SupportsMultipleKeyboardsAndMice = true;

//Game files
Game.HandlerInterval = 100;
Game.SymlinkExe = false;
Game.SymlinkGame = true;
Game.SymlinkFolders = true;
Game.ExecutableName = "openttd.exe";
Game.GUID = "OpenTTD";
Game.GameName = "OpenTTD";
Game.MaxPlayers = 16;
Game.MaxPlayersOneMonitor = 8;

//Window
Game.Hook.ForceFocus = true;
Game.Hook.ForceFocusWindowName = "OpenTTD";
Game.HasDynamicWindowTitle = true;
Game.WindowStyleEndChanges = ["~0xC00000", "0x8000000"];
Game.RefreshWindowAfterStart = true;
Game.ToggleUnfocusOnInputsLock = true;
Game.SetTopMostAtEnd = true;

//Environment
Game.UseNucleusEnvironment = true;
Game.DocumentsConfigPath = "OpenTTD";

//Controllers
Game.Hook.DInputEnabled = false;
Game.Hook.XInputEnabled = false;
Game.Hook.XInputReroute = false;
Game.Hook.CustomDllEnabled = false;

//Description
Game.Description =
  "Handler for OpenTTD: https://www.openttd.org/. Keyboards/mice only. After all the instances have launched, resized and positioned correctly, press the END key once to lock the input for all instances to have their own working cursor, you need to left click each mouse to make the emulated cursors appear after locking the input. Press the END key again to unlock the input when you finish playing.";

//USS deprecated options:
Game.HookSetCursorPos = false;
Game.HookGetCursorPos = false;
Game.HookGetKeyState = false;
Game.HookGetAsyncKeyState = false;
Game.HookGetKeyboardState = false;
Game.HookFilterRawInput = false;
Game.HookFilterMouseMessages = false;
Game.HookUseLegacyInput = false;
Game.HookDontUpdateLegacyInMouseMsg = false;
Game.HookMouseVisibility = false;
Game.InjectHookXinput = false;
Game.SendNormalMouseInput = false;
Game.SendNormalKeyboardInput = false;
Game.SendScrollWheel = false;
Game.ForwardRawKeyboardInput = false;
Game.ForwardRawMouseInput = false;
Game.HookReRegisterRawInput = false;
Game.HookReRegisterRawInputMouse = false;
Game.HookReRegisterRawInputKeyboard = false;
Game.DrawFakeMouseCursor = false;
Game.LockInputAtStart = false;

//ProtoInput
Game.ProtoInput.AutoHideTaskbar = true;
Game.LockInputSuspendsExplorer = true;
Game.ProtoInput.FreezeExternalInputWhenInputNotLocked = false;
Game.ProtoInput.InjectStartup = false;
Game.ProtoInput.InjectRuntime_RemoteLoadMethod = false;
Game.ProtoInput.InjectRuntime_EasyHookMethod = false; // Usually this works best
Game.ProtoInput.InjectRuntime_EasyHookStealthMethod = true;
Game.ProtoInput.RegisterRawInputHook = true;
Game.ProtoInput.GetRawInputDataHook = true;
Game.ProtoInput.RawInputFilter = true;
Game.ProtoInput.MessageFilterHook = true;
Game.ProtoInput.GetCursorPosHook = true;
Game.ProtoInput.SetCursorPosHook = true;
Game.ProtoInput.GetKeyStateHook = true;
Game.ProtoInput.GetAsyncKeyStateHook = true;
Game.ProtoInput.GetKeyboardStateHook = true;
Game.ProtoInput.CursorVisibilityHook = true;
Game.ProtoInput.ClipCursorHook = true;
Game.ProtoInput.ClipCursorHookCreatesFakeClip = false;
Game.ProtoInput.AllowFakeCursorOutOfBounds = false;
Game.ProtoInput.FocusHooks = true;
Game.ProtoInput.DrawFakeCursor = false;
Game.ProtoInput.MouseMoveFilter = false;
Game.ProtoInput.MouseActivateFilter = true;
Game.ProtoInput.WindowActivateFilter = true;
Game.ProtoInput.WindowActvateAppFilter = true;
Game.ProtoInput.MouseWheelFilter = true;
Game.ProtoInput.MouseButtonFilter = true;
Game.ProtoInput.KeyboardButtonFilter = true;
Game.ProtoInput.SendMouseWheelMessages = true;
Game.ProtoInput.SendMouseButtonMessages = true;
Game.ProtoInput.SendMouseMovementMessages = true;
Game.ProtoInput.SendKeyboardButtonMessages = true;
Game.ProtoInput.XinputHook = false;
Game.ProtoInput.UseDinputRedirection = false;
Game.ProtoInput.UseOpenXinput = false;
Game.ProtoInput.DinputDeviceHook = false;
Game.ProtoInput.DinputHookAlsoHooksGetDeviceState = false;
Game.ProtoInput.EnableFocusMessageLoop = false;
Game.ProtoInput.FocusLoopIntervalMilliseconds = 5;
Game.ProtoInput.FocusLoop_WM_ACTIVATE = false;
Game.ProtoInput.FocusLoop_WM_ACTIVATEAPP = false;
Game.ProtoInput.FocusLoop_WM_NCACTIVATE = false;
Game.ProtoInput.FocusLoop_WM_SETFOCUS = false;
Game.ProtoInput.FocusLoop_WM_MOUSEACTIVATE = false;
Game.ProtoInput.WindowActivateFilter = false; // Filters take priority over blocks, so disable the filter
Game.ProtoInput.BlockedMessages = [0x0008, 0x2a3]; // Blocks WM_KILLFOCUS //WM_MOUSELEAVE

Game.PauseBetweenContextAndLaunch = 2;
Game.PauseBetweenProcessGrab = 5;
Game.PauseBetweenStarts = 10;

Game.Play = function() {
  var music = Context.Options["Music"];
  var volume = Context.Options["Volume"];
  var sfvolume = Context.Options["SFVolume"];
  var interface = Context.Options["Interface"];
  var initpos = Context.Options["Initpos"];
  var txtPath = Context.EnvironmentPlayer + "\\Documents\\OpenTTD\\openttd.cfg";
  var dict = [
    Context.FindLineNumberInTextFile(txtPath, "resolution = ", Nucleus.SearchType.StartsWith) + "|resolution = " + Context.Width + "," + Context.Height,
    Context.FindLineNumberInTextFile(txtPath, "fullscreen = ", Nucleus.SearchType.StartsWith) + "|fullscreen = false",
    Context.FindLineNumberInTextFile(txtPath, "video_vsync = ", Nucleus.SearchType.StartsWith) + "|video_vsync = true",
    Context.FindLineNumberInTextFile(txtPath, "effect_vol = ", Nucleus.SearchType.StartsWith) + "|effect_vol = " + sfvolume
  ];
  Context.ReplaceLinesInTextFile(txtPath, dict);
  if (music == "ONE") {
    if (Context.PlayerID == 0) {
      var dict = [Context.FindLineNumberInTextFile(txtPath, "music_vol = ", Nucleus.SearchType.StartsWith) + "|music_vol = " + volume];
      Context.ReplaceLinesInTextFile(txtPath, dict);
    }
    if (Context.PlayerID > 0) {
      var dict = [Context.FindLineNumberInTextFile(txtPath, "music_vol = ", Nucleus.SearchType.StartsWith) + "|music_vol = 0"];
      Context.ReplaceLinesInTextFile(txtPath, dict);
    }
  }
  if (music == "ALL") {
    var dict = [Context.FindLineNumberInTextFile(txtPath, "music_vol = ", Nucleus.SearchType.StartsWith) + "|music_vol = " + volume];
    Context.ReplaceLinesInTextFile(txtPath, dict);
  }
  if (music == "NONE") {
    var dict = [Context.FindLineNumberInTextFile(txtPath, "music_vol = ", Nucleus.SearchType.StartsWith) + "|music_vol = 0"];
    Context.ReplaceLinesInTextFile(txtPath, dict);
  }
  if (interface != "No Change") {
    var dict = [Context.FindLineNumberInTextFile(txtPath, "gui_scale = ", Nucleus.SearchType.StartsWith) + "|gui_scale = " + interface];
    Context.ReplaceLinesInTextFile(txtPath, dict);
  }
  var txtPath = Context.EnvironmentPlayer + "\\Documents\\OpenTTD\\private.cfg";
  var dict = [
    Context.FindLineNumberInTextFile(txtPath, "client_name = ", Nucleus.SearchType.StartsWith) + "|client_name = " + Context.Nickname,
    Context.FindLineNumberInTextFile(txtPath, "server_name = ", Nucleus.SearchType.StartsWith) + "|server_name = nucleus server",
    Context.FindLineNumberInTextFile(txtPath, "connect_to_ip = ", Nucleus.SearchType.StartsWith) + "|connect_to_ip = 127.0.0.1",
    Context.FindLineNumberInTextFile(txtPath, "last_joined = ", Nucleus.SearchType.StartsWith) + "|last_joined = 127.0.0.1"
  ];
  Context.ReplaceLinesInTextFile(txtPath, dict);
  if (initpos == "Yes") {
    Game.PauseBetweenProcessGrab = 1;
    Game.PauseBetweenStarts = 0;
    for (var i = 0; i < 2; i++) {
      if (i == 0) {
        var j = Context.PosY;
      }
      if (i == 1) {
        var j = Context.PosX;
      }
      var k = "0000";
      if (j == "200") {
        k = "C800";
      }
      if (j == "240") {
        k = "F000";
      }
      if (j == "320") {
        k = "4001";
      }
      if (j == "480") {
        k = "E001";
      }
      if (j == "525") {
        k = "0D02";
      }
      if (j == "540") {
        k = "1C02";
      }
      if (j == "576") {
        k = "4002";
      }
      if (j == "600") {
        k = "5802";
      }
      if (j == "640") {
        k = "8002";
      }
      if (j == "704") {
        k = "C002";
      }
      if (j == "720") {
        k = "D002";
      }
      if (j == "768") {
        k = "0003";
      }
      if (j == "800") {
        k = "2003";
      }
      if (j == "840") {
        k = "4803";
      }
      if (j == "848") {
        k = "5003";
      }
      if (j == "854") {
        k = "5603";
      }
      if (j == "900") {
        k = "8403";
      }
      if (j == "960") {
        k = "C003";
      }
      if (j == "992") {
        k = "E003";
      }
      if (j == "1000") {
        k = "E803";
      }
      if (j == "1024") {
        k = "0004";
      }
      if (j == "1050") {
        k = "1A04";
      }
      if (j == "1080") {
        k = "3804";
      }
      if (j == "1152") {
        k = "8004";
      }
      if (j == "1200") {
        k = "B004";
      }
      if (j == "1280") {
        k = "0005";
      }
      if (j == "1360") {
        k = "5005";
      }
      if (j == "1366") {
        k = "5605";
      }
      if (j == "1368") {
        k = "5805";
      }
      if (j == "1440") {
        k = "A005";
      }
      if (j == "1536") {
        k = "0006";
      }
      if (j == "1600") {
        k = "4006";
      }
      if (j == "1680") {
        k = "9006";
      }
      if (j == "1768") {
        k = "E806";
      }
      if (j == "1776") {
        k = "F006";
      }
      if (j == "1800") {
        k = "0807";
      }
      if (j == "1920") {
        k = "8007";
      }
      if (j == "2048") {
        k = "0008";
      }
      if (j == "2160") {
        k = "7008";
      }
      if (j == "2400") {
        k = "6009";
      }
      if (j == "2560") {
        k = "000A";
      }
      if (j == "2720") {
        k = "A00A";
      }
      if (j == "2880") {
        k = "400B";
      }
      if (j == "3072") {
        k = "000C";
      }
      if (j == "3200") {
        k = "800C";
      }
      if (j == "3360") {
        k = "200D";
      }
      if (j == "3440") {
        k = "700D";
      }
      if (j == "3840") {
        k = "000F";
      }
      if (j == "4080") {
        k = "F00F";
      }
      if (j == "4320") {
        k = "E010";
      }
      if (j == "4800") {
        k = "C012";
      }
      if (j == "5040") {
        k = "B013";
      }
      if (j == "5120") {
        k = "0014";
      }
      if (j == "5760") {
        k = "8016";
      }
      if (i == 0) {
        var POSY = k;
      }
      if (i == 1) {
        var POSX = k;
      }
    }
    //windowstyle
    Context.PatchFileFindPattern(
      System.IO.Path.Combine(Context.RootFolder, "Openttd.exe"),
      System.IO.Path.Combine(Context.RootFolder, "Openttd.exe"),
      "41 BD 00 00 CF 00 80 3D FA E0 8E 00 00 44 0F 45",
      "41 BD 00 00 00 80 80 3D FA E0 8E 00 00 44 0F 45",
      true
    );
    Context.Wait(500);
    //Y pos
    Context.PatchFileFindPattern(
      System.IO.Path.Combine(Context.RootFolder, "Openttd.exe"),
      System.IO.Path.Combine(Context.RootFolder, "Openttd.exe"),
      "99 2B C2 D1 F8 8B F0 EB 03 41 8B F4 48 8D 4D A8",
      "B8" + POSY + "00 00 8B F0 EB 03 41 8B F4 48 8D 4D A8",
      true
    );
    Context.Wait(500);
    //X pos
    Context.PatchFileFindPattern(
      System.IO.Path.Combine(Context.RootFolder, "Openttd.exe"),
      System.IO.Path.Combine(Context.RootFolder, "Openttd.exe"),
      "2B C7 99 2B C2 D1 F8 44 8B E0 8B 45 A0 2B 45 98",
      "99 90 B8" + POSX + "00 00 44 8B E0 8B 45 A0 2B 45 98",
      true
    );
  }
  Game.ProtoInput.OnInputLocked = function() {
    for (var i = 0; i < PlayerList.Count; i++) {
      var player = PlayerList[i];
      ProtoInput.StartFocusMessageLoop(player.ProtoInputInstanceHandle, 0, true, true, true, true, true);
      System.Threading.Thread.Sleep(1000);
      ProtoInput.StopFocusMessageLoop(player.ProtoInputInstanceHandle);
    }
  };
};