Skip to content

Instantly share code, notes, and snippets.

@CryZe
Created February 15, 2026 17:41
Show Gist options
  • Select an option

  • Save CryZe/ff345df62a73e06f3ae32572e746c145 to your computer and use it in GitHub Desktop.

Select an option

Save CryZe/ff345df62a73e06f3ae32572e746c145 to your computer and use it in GitHub Desktop.
A Hat in Time LibreSplit Auto Splitter
local function default_settings()
local s = {
settings_ILMode = false,
settings_newFileStart = true,
settings_gameTimeMsg = true,
splits = true,
splits_tp = true,
splits_tp_new = true,
splits_tp_any = true,
splits_tp_std = true,
splits_actEntry = false,
splits_checkpoint = false,
splits_yarn = false,
splits_dwbth = false,
splits_dwbth_doubleSplitNo = true,
manySplits = false,
manySplits_riftBlue = true,
manySplits_riftPurple = true,
manySplits_4_99_entry = false,
manySplits_4_99_cp0_pause_pos = false,
manySplits_pos_40 = false,
manySplits_pos_41 = false,
manySplits_pos_42 = false,
manySplits_pos_43 = false,
manySplits_pos_44 = false,
manySplits_pos_45 = false,
manySplits_5_1_cp1 = false,
manySplits_5_1_cp2 = false,
manySplits_5_1_cp3 = false,
manySplits_pos_5 = false,
manySplits_5_1_cp10 = false,
manySplits_1_1_cp1 = false,
manySplits_1_2_cp1 = false,
manySplits_1_3_cp1 = false,
manySplits_1_4_cp0_pause_pos = false,
manySplits_1_4_cp1 = false,
manySplits_1_4_cp2 = false,
manySplits_1_6_cp59_pause = false,
manySplits_2_1_cp5 = false,
manySplits_2_4_cp1 = false,
manySplits_2_4_cp4 = false,
manySplits_2_5_cp1 = false,
manySplits_2_5_cp2 = false,
manySplits_2_5_cp3 = false,
manySplits_2_6_cp0_pause_pos = false,
manySplits_3_2_cp0_pause_pos = false,
manySplits_3_3_cp1 = false,
manySplits_3_4_cp0_pause_pos = false,
manySplits_3_6_cp1 = false,
manySplits_6_1_cp3 = false,
manySplits_6_2_cp1 = false,
manySplits_6_3_cp1 = false,
manySplits_6_3_cp2 = false,
manySplits_6_3_cp3 = false,
}
local act_names = {
{"Welcome to Mafia Town", "Barrel Battle", "She Came From Outer Space", "Down With The Mafia!", "Cheating The Race", "Heating Up Mafia Town", "The Golden Vault"},
{"Dead Bird Studio", "Murder on the Owl Express", "Picture Perfect", "Train Rush", "The Big Parade", "Award Ceremony", ""},
{"Contractual Obligations", "The Subcon Well", "Toilet of Doom", "Queen Vanessa's Manor", "Mail Delivery Service", "Your Contract Has Expired", ""},
{"Bon Voyage!", "Ship Shape", "Rock The Boat", "", "", "", ""},
}
for i = 1, 7 do
s["manySplits_" .. i] = true
end
for j = 1, 7 do
for i = 1, 7 do
if j <= 4 and act_names[j][i] ~= "" then
local chapter = (j == 4) and 6 or j
s["manySplits_" .. chapter .. "_" .. i] = true
s["manySplits_" .. chapter .. "_" .. i .. "_entry"] = false
s["manySplits_" .. chapter .. "_" .. i .. "_tp"] = true
s["manySplits_" .. chapter .. "_" .. i .. "_tpDelayed"] = false
else
break
end
end
if j == 5 or j == 7 then
s["manySplits_" .. j .. "_entry"] = false
end
if j == 4 or j == 5 or j == 7 then
s["manySplits_" .. j .. "_tp"] = true
end
end
local rift_ids = {
{"gallery", "lab", "sewers", "bazaar", "owlExpress", "moon", "village", "pipe", "twilight", "curly", "balcony"},
{"moc", "dbs", "sleepy", "alpine", "deepSea", "rumbi", "tour", "", "", "", ""},
}
for i = 1, 11 do
local blue = rift_ids[1][i]
s["manySplits_riftBlue_" .. blue] = true
s["manySplits_riftBlue_" .. blue .. "_entry"] = false
s["manySplits_riftBlue_" .. blue .. "_tp"] = true
local purple = rift_ids[2][i]
if purple ~= "" then
s["manySplits_riftPurple_" .. purple] = true
s["manySplits_riftPurple_" .. purple .. "_entry"] = false
s["manySplits_riftPurple_" .. purple .. "_cp"] = false
s["manySplits_riftPurple_" .. purple .. "_tp"] = true
end
end
return s
end
local SETTINGS = default_settings()
local function enabled(key)
return SETTINGS[key] == true
end
local SIG_TIMER = "54 49 4D 52 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 45 4E 44 20"
local SIG_SAVE_VACU = "48 8B 1D ?? ?? ?? ?? 48 85 DB 74 ?? 48 8B 5B ?? 48 85 DB 74 ??"
local SIG_SAVE_DLC = "48 8B 05 ?? ?? ?? ?? 48 8B 74 24 ?? 48 83 C4 50"
local SIG_SAVE_MOD = "48 8B 05 ?? ?? ?? ?? 48 8B D9 48 85 C0 75 ?? 48 89 7C 24 ??"
local SIG_SAVE_REL = "48 8B 05 ?? ?? ?? ?? 48 8B 7C 24 ?? 48 83 C4 40"
local SIG_ACTORS = "48 8B 05 ?? ?? ?? ?? 81 88 ?? ?? ?? ?? 00 00 80 00"
local SIG_HATKID = "48 8B 81 ?? ?? ?? ?? 4C 8D 80 ?? ?? ?? ??"
local vars = {
initialized = false,
saveDataPtrType = "none",
timerPtr = nil,
saveDataPtrAddress = nil,
actorsPtrAddress = nil,
coordsOffsetPtrAddress = nil,
saveDataAddressFinal = nil,
actorsAddressFinal = nil,
hatKidOffset = nil,
lastChapter = 0,
gameTimeFinal = 0.0,
savedGameTime = 0.0,
splitInLoadScreen = false,
currentRift = "none",
justEnteredRift = false,
posSplitKey = 0.0,
splitLockMs = 0,
current = {},
old = {},
nextScanAt = 0,
}
local posSplitKeysDict = {
[4] = {
{-11000, -9000, 32000, 34000, -1000, 500, 40},
{36500, 38000, -13000, -11000, 4500, 5500, 41},
{47000, 49000, 21000, 22000, 1000, 2500, 42},
{7000, 8500, 43000, 45000, -1000, 1000, 43},
{-15300, -14400, 47750, 49000, -1650, -1300, 44},
{41000, 42500, 29000, 30500, 2400, 2800, 45},
},
[5] = {
{-30000, -28000, -2, -2, -2, -2, 5},
},
}
local posSplitsDict = {
[40] = {-24000, -23000, 29000, 30500, 4000, 6000},
[41] = {3000, 30400, -28500, -27353, 3200, 4000},
[42] = {71600, 72300, 21500, 22700, 1500, 2100},
[43] = {4600, 8700, 69000, 70000, 4000, 5400},
[44] = {-2, -2, -2, -2, -2, -9680},
[45] = {-2, -2, -2, -2, -2, -4230},
[5] = {-38300, -38190, -85000, -84000, -2, -2},
}
local function now_ms()
return math.floor(os.clock() * 1000)
end
local function rip_relative_target(addr)
local rel = readAddress("int", addr)
if rel == nil then
return nil
end
return addr + rel + 4
end
local function read_chain(ty, base, offsets)
if base == nil then
return nil
end
if offsets == nil or #offsets == 0 then
return readAddress(ty, base)
end
local args = {ty, base}
for i = 1, #offsets do
args[#args + 1] = offsets[i]
end
return readAddress(table.unpack(args))
end
local function deep_read(ty, root, ...)
local offsets = {...}
return read_chain(ty, root, offsets)
end
local function in_range(v, lo, hi)
return v > lo and v < hi
end
local function pos_match(x, y, z, p)
return (x > p[1] or p[1] == -2) and (x < p[2] or p[2] == -2)
and (y > p[3] or p[3] == -2) and (y < p[4] or p[4] == -2)
and (z > p[5] or p[5] == -2) and (z < p[6] or p[6] == -2)
end
local function current_rift_check(chapter, x, y, z)
if (chapter == 1 and in_range(x, 4070, 4250) and in_range(y, -5550, -5350) and in_range(z, -900, -700))
or (chapter == 1 and in_range(x, 13200, 13250) and in_range(y, -120, -80) and z > -250)
then
return "manySplits_riftPurple_moc"
elseif (chapter == 2 and in_range(x, 8350, 8500) and in_range(y, -2250, -2100) and in_range(z, 2700, 2870))
or (chapter == 2 and in_range(x, 7750, 7800) and in_range(y, -10500, -10400) and z > 1000)
then
return "manySplits_riftPurple_dbs"
elseif (chapter == 3 and in_range(x, 13100, 13300) and in_range(y, 25150, 25350) and in_range(z, 2300, 2500))
or (chapter == 3 and in_range(x, 6100, 6150) and in_range(y, 32400, 32500) and z > 550)
then
return "manySplits_riftPurple_sleepy"
elseif (chapter == 4 and in_range(x, 16700, 16850) and in_range(y, 28750, 28900) and in_range(z, -5100, -4800))
or (chapter == 4 and in_range(x, -11700, -11600) and in_range(y, -11700, -11600) and z > -4000)
then
return "manySplits_riftPurple_alpine"
elseif (chapter == 6 and in_range(x, 1860, 3000) and in_range(y, 6400, 6550) and in_range(z, 4000, 4200))
or (chapter == 6 and in_range(x, -15700, -15600) and in_range(y, 870, 910) and z > 3200)
then
return "manySplits_riftPurple_deepSea"
elseif (chapter == 7 and in_range(x, 750, 900) and in_range(y, 1200, 1350) and in_range(z, 1250, 1450))
or (chapter == 7 and in_range(x, -400, -300) and in_range(y, -8400, -8300) and z > 1000)
then
return "manySplits_riftPurple_rumbi"
elseif (in_range(x, -4220, -4120) and in_range(y, -800, -710) and in_range(z, 1300, 1500))
or (in_range(x, 13100, 13200) and in_range(y, -250, -200) and z > 2650)
then
return "manySplits_riftPurple_tour"
elseif (chapter == 1 and in_range(x, -200, -150) and in_range(y, -410, -360) and in_range(z, 60, 120))
or (chapter == 1 and in_range(x, 640, 850) and in_range(y, 4000, 4140) and in_range(z, 760, 960))
then
return "manySplits_riftBlue_sewers"
elseif (chapter == 1 and in_range(x, -200, -150) and in_range(y, -150, -120) and in_range(z, 60, 120))
or (chapter == 1 and in_range(x, -3150, -3030) and in_range(y, -2480, -2360) and in_range(z, 400, 600))
then
return "manySplits_riftBlue_bazaar"
elseif (chapter == 2 and in_range(x, -2710, -2500) and in_range(y, 1020, 1230) and in_range(z, 10, 100))
or (chapter == 2 and in_range(x, -53920, -53810) and in_range(y, -9260, -9150) and in_range(z, 100, 290))
then
return "manySplits_riftBlue_owlExpress"
elseif (chapter == 2 and in_range(x, 2600, 2850) and in_range(y, 850, 1100) and in_range(z, 0, 100))
or (chapter == 2 and in_range(x, -3950, -3830) and in_range(y, -100, 0) and in_range(z, 390, 570))
then
return "manySplits_riftBlue_moon"
elseif (chapter == 3 and in_range(x, -2800, -2400) and in_range(y, -1800, -1450) and in_range(z, 60, 120))
or (chapter == 3 and in_range(x, 1190, 1290) and in_range(y, 26250, 26350) and in_range(z, 3450, 3630))
then
return "manySplits_riftBlue_village"
elseif (chapter == 3 and in_range(x, 1780, 2000) and in_range(y, -11384, -9350) and in_range(z, 60, 120))
or (chapter == 3 and in_range(x, -130, -20) and in_range(y, 7250, 7360) and in_range(z, 500, 640))
then
return "manySplits_riftBlue_pipe"
elseif (chapter == 4 and in_range(x, 7600, 7900) and in_range(y, 1100, 1400) and in_range(z, -500, -100))
or (chapter == 4 and in_range(x, 6330, 6450) and in_range(y, 72060, 72180) and in_range(z, 5150, 5300))
then
return "manySplits_riftBlue_twilight"
elseif (chapter == 4 and in_range(x, 5700, 6000) and in_range(y, 3100, 3400) and in_range(z, -500, -100))
or (chapter == 4 and in_range(x, 56380, 56500) and in_range(y, 6740, 6840) and in_range(z, -1690, -1500))
then
return "manySplits_riftBlue_curly"
elseif (chapter == 6 and in_range(x, 3700, 3950) and in_range(y, 4300, 4550) and in_range(z, 1200, 1400))
or (chapter == 6 and in_range(x, -950, -840) and in_range(y, -1410, -1310) and in_range(z, 7690, 7850))
then
return "manySplits_riftBlue_balcony"
elseif (in_range(x, -1180, -920) and in_range(y, 4050, 4350) and in_range(z, 200, 300))
or (in_range(x, -3940, -3840) and in_range(y, -80, 20) and in_range(z, -520, -350))
then
return "manySplits_riftBlue_lab"
elseif (in_range(x, 7250, 7550) and in_range(y, 100, 400) and in_range(z, -500, -400))
or (in_range(x, 3100, 3220) and in_range(y, -2400, -2270) and in_range(z, 130, 310))
then
return "manySplits_riftBlue_gallery"
end
return "none"
end
local function back_to_hub_check(chapter, x, y, z)
return (in_range(x, -690, -660) and in_range(y, 1525, 1555) and in_range(z, 225, 260))
or (chapter == 1 and in_range(x, 195, 425) and in_range(y, 0, 200))
or (chapter == 2 and in_range(x, 2345, 2555) and in_range(y, 110, 320) and in_range(z, 0, 200))
or (chapter == 2 and in_range(x, 2300, 2550) and in_range(y, -160, 60) and in_range(z, 0, 200))
or (chapter == 3 and in_range(x, -2120, -1910) and in_range(y, -2010, -1800) and in_range(z, 0, 150))
or (chapter == 4 and in_range(x, -690, -480) and in_range(y, -4065, -3855) and in_range(z, -325, -240))
or (chapter == 5 and in_range(x, -1365, -1155) and in_range(y, -125, 85) and in_range(z, 280, 350))
or (chapter == 6 and in_range(x, 19365, 21375) and in_range(y, -24840, -22830) and in_range(z, 1200, 1400))
or (chapter == 7 and in_range(x, 25260, 27270) and in_range(y, -24015, -22005) and in_range(z, 1190, 1500))
or (chapter == 97 and in_range(x, -2410, -2200) and in_range(y, -2185, -1975) and in_range(z, -65, 200))
or (chapter == 99 and in_range(x, 1500, 1710) and in_range(y, 1525, 1735) and in_range(z, 400, 500))
end
local function should_split_at_this_pos_pause(chapter, x, y, z)
return (chapter == 1 and enabled("manySplits_1_4_cp0_pause_pos") and in_range(x, 3500, 4500) and in_range(y, -3500, -3000) and in_range(z, 8000, 9000))
or (chapter == 2 and enabled("manySplits_2_6_cp0_pause_pos") and in_range(x, 5500, 9500) and in_range(y, 5000, 12000) and z < 4000)
or (chapter == 3 and enabled("manySplits_3_2_cp0_pause_pos") and in_range(x, 15800, 17000) and in_range(y, 10900, 11900) and z < 2000)
or (chapter == 3 and enabled("manySplits_3_4_cp0_pause_pos") and in_range(x, -28000, -26000) and in_range(y, 2000, 3400) and in_range(z, 200, 1200))
or (chapter == 4 and enabled("manySplits_4_99_cp0_pause_pos") and in_range(x, 37000, 41000) and in_range(y, 47000, 51000) and in_range(z, -14000, -5000))
end
local function emit_split()
vars.splitLockMs = now_ms()
vars.posSplitKey = 0
return true
end
local function elapsed_ms()
return now_ms() - vars.splitLockMs
end
local function try_initialize()
if now_ms() < vars.nextScanAt then
return false
end
vars.timerPtr = vars.timerPtr or sig_scan(SIG_TIMER, 0)
if vars.timerPtr == nil then
vars.nextScanAt = now_ms() + 1000
return false
end
if vars.saveDataPtrAddress == nil then
local addr = sig_scan(SIG_SAVE_VACU, 3)
if addr ~= nil then
vars.saveDataPtrType = "DLCPtr"
vars.saveDataPtrAddress = addr
end
end
if vars.saveDataPtrAddress == nil then
local addr = sig_scan(SIG_SAVE_DLC, 3)
if addr ~= nil then
vars.saveDataPtrType = "DLCPtr"
vars.saveDataPtrAddress = addr
end
end
if vars.saveDataPtrAddress == nil then
local addr = sig_scan(SIG_SAVE_MOD, 3)
if addr ~= nil then
vars.saveDataPtrType = "ModdingPtr"
vars.saveDataPtrAddress = addr
end
end
if vars.saveDataPtrAddress == nil then
local addr = sig_scan(SIG_SAVE_REL, 3)
if addr ~= nil then
vars.saveDataPtrType = "1.0Ptr"
vars.saveDataPtrAddress = addr
end
end
vars.actorsPtrAddress = vars.actorsPtrAddress or sig_scan(SIG_ACTORS, 3)
vars.coordsOffsetPtrAddress = vars.coordsOffsetPtrAddress or sig_scan(SIG_HATKID, 3)
if vars.saveDataPtrAddress == nil or vars.actorsPtrAddress == nil or vars.coordsOffsetPtrAddress == nil then
vars.nextScanAt = now_ms() + 1000
return false
end
vars.saveDataAddressFinal = rip_relative_target(vars.saveDataPtrAddress)
vars.actorsAddressFinal = rip_relative_target(vars.actorsPtrAddress)
vars.hatKidOffset = readAddress("int", vars.coordsOffsetPtrAddress)
if vars.saveDataAddressFinal == nil or vars.actorsAddressFinal == nil or vars.hatKidOffset == nil then
vars.nextScanAt = now_ms() + 1000
return false
end
local guard = readAddress("int", vars.saveDataAddressFinal)
if guard == nil or guard == 0 then
vars.nextScanAt = now_ms() + 1000
return false
end
local guard_actors = readAddress("int", vars.actorsAddressFinal)
if guard_actors == nil or guard_actors == 0 then
vars.nextScanAt = now_ms() + 1000
return false
end
vars.initialized = true
print("[ahit] initialized memory signatures")
return true
end
local function read_game_state()
vars.old = shallow_copy_tbl(vars.current)
vars.current = {}
local c = vars.current
c.timerState = readAddress("int", vars.timerPtr + 0x04)
c.unpauseTime = readAddress("double", vars.timerPtr + 0x08)
c.gameTimerIsPaused = readAddress("int", vars.timerPtr + 0x10)
c.actTimerIsPaused = readAddress("int", vars.timerPtr + 0x14)
c.actTimerIsVisible = readAddress("int", vars.timerPtr + 0x18)
c.unpauseTimeIsDirty = readAddress("int", vars.timerPtr + 0x1C)
c.justGotTimePiece = readAddress("int", vars.timerPtr + 0x20)
c.gameTime = readAddress("double", vars.timerPtr + 0x24)
c.actTime = readAddress("double", vars.timerPtr + 0x2C)
c.realGameTime = readAddress("double", vars.timerPtr + 0x34)
c.realActTime = readAddress("double", vars.timerPtr + 0x3C)
c.timePieceCount = readAddress("int", vars.timerPtr + 0x44)
if vars.saveDataPtrType == "DLCPtr" then
c.yarn = deep_read("int", vars.saveDataAddressFinal, 0x68, 0xF0)
c.chapter = deep_read("int", vars.saveDataAddressFinal, 0x68, 0x108)
c.act = deep_read("int", vars.saveDataAddressFinal, 0x68, 0x10C)
c.checkpoint = deep_read("int", vars.saveDataAddressFinal, 0x68, 0x110)
elseif vars.saveDataPtrType == "ModdingPtr" then
c.yarn = deep_read("int", vars.saveDataAddressFinal, 0x64, 0xE0)
c.chapter = deep_read("int", vars.saveDataAddressFinal, 0x64, 0xF8)
c.act = deep_read("int", vars.saveDataAddressFinal, 0x64, 0xFC)
c.checkpoint = deep_read("int", vars.saveDataAddressFinal, 0x64, 0x100)
else
c.yarn = deep_read("int", vars.saveDataAddressFinal, 0x64, 0xE0)
c.chapter = deep_read("int", vars.saveDataAddressFinal, 0x64, 0xF4)
c.act = deep_read("int", vars.saveDataAddressFinal, 0x64, 0xF8)
c.checkpoint = deep_read("int", vars.saveDataAddressFinal, 0x64, 0xFC)
end
c.x = deep_read("float", vars.actorsAddressFinal, 0x6DC, 0x00, 0x68, vars.hatKidOffset, 0x80)
c.y = deep_read("float", vars.actorsAddressFinal, 0x6DC, 0x00, 0x68, vars.hatKidOffset, 0x84)
c.z = deep_read("float", vars.actorsAddressFinal, 0x6DC, 0x00, 0x68, vars.hatKidOffset, 0x88)
end
local function all_position_values_available(c)
return c.chapter ~= nil and c.x ~= nil and c.y ~= nil and c.z ~= nil
end
function startup()
process("HatinTimeGame", "first")
useGameTime = true
mapsCacheCycles = 2
end
function state()
if not vars.initialized and not try_initialize() then
return
end
read_game_state()
local c = vars.current
local o = vars.old
if c.chapter ~= nil and o.chapter ~= nil and c.chapter ~= o.chapter then
vars.lastChapter = o.chapter
end
vars.gameTimeFinal = c.realGameTime or 0.0
if c.actTimerIsVisible == 1 and o.actTimerIsVisible == 0 and c.gameTime ~= nil then
vars.savedGameTime = c.gameTime
end
if (c.timePieceCount ~= nil and o.timePieceCount ~= nil and c.timePieceCount == o.timePieceCount + 1)
or (c.justGotTimePiece == 1 and o.justGotTimePiece == 0)
then
if enabled("manySplits_" .. tostring(c.chapter) .. "_" .. tostring(c.act) .. "_tpDelayed") then
vars.splitInLoadScreen = true
end
if c.realActTime ~= nil and c.realGameTime ~= nil then
local candidate = vars.savedGameTime + c.realActTime
if candidate > c.realGameTime - 0.1 and candidate < c.realGameTime + 0.1 then
vars.gameTimeFinal = candidate
end
end
end
if c.gameTimerIsPaused == 0 and o.gameTimerIsPaused == 1 then
vars.splitInLoadScreen = false
vars.posSplitKey = 0
if all_position_values_available(c) and back_to_hub_check(c.chapter, c.x, c.y, c.z) then
vars.currentRift = "none"
end
end
if c.timerState == 0 then
vars.currentRift = "none"
end
if vars.justEnteredRift then
vars.justEnteredRift = false
end
if c.gameTimerIsPaused ~= o.gameTimerIsPaused and vars.currentRift == "none" and enabled("manySplits") and all_position_values_available(c) then
vars.currentRift = current_rift_check(c.chapter, c.x, c.y, c.z)
if vars.currentRift ~= "none" then
vars.justEnteredRift = true
end
end
if (c.chapter == 4 or c.chapter == 5) and all_position_values_available(c) then
local chapter_positions = posSplitKeysDict[c.chapter]
if chapter_positions ~= nil then
for i = 1, #chapter_positions do
local position = chapter_positions[i]
if pos_match(c.x, c.y, c.z, position) then
vars.posSplitKey = position[7]
end
end
end
end
end
function gameTime()
if enabled("settings_ILMode") then
return math.floor((vars.current.realActTime or 0) * 1000)
end
return math.floor((vars.gameTimeFinal or 0) * 1000)
end
function start()
local c = vars.current
local o = vars.old
if c.timerState == nil or o.timerState == nil then
return false
end
if enabled("settings_newFileStart") and c.timerState == 1 and o.timerState == 0 and (c.timePieceCount == 0 or c.timePieceCount == -1) then
return true
end
if (not enabled("settings_newFileStart")) and c.timerState == 1 and o.timerState == 0 then
return true
end
if enabled("settings_ILMode") and c.actTimerIsVisible == 1 and (c.realActTime or -1) == 0 then
return true
end
return false
end
function split()
local c = vars.current
local o = vars.old
if c.timerState == nil or o.timerState == nil then
return false
end
if elapsed_ms() <= 1000 or c.timerState == 0 then
return false
end
local tp_new = c.timePieceCount ~= nil and o.timePieceCount ~= nil and c.timePieceCount == o.timePieceCount + 1
local tp_any = c.justGotTimePiece == 1 and o.justGotTimePiece == 0
if enabled("splits") then
if tp_new and enabled("splits_tp_new") then
return emit_split()
end
if tp_any and enabled("splits_tp_any") then
return emit_split()
end
if c.actTimerIsVisible == 1 and o.actTimerIsVisible == 0 and vars.currentRift == "none" and enabled("splits_actEntry") and not enabled("settings_ILMode") then
return emit_split()
end
if tp_any and c.chapter == 3 and vars.lastChapter == 5 and enabled("splits_tp_std") then
return emit_split()
end
if c.chapter == 97 and o.chapter ~= 97 and enabled("splits_dwbth") then
if (enabled("splits_dwbth_doubleSplitNo") and elapsed_ms() > 9000) or (not enabled("splits_dwbth_doubleSplitNo")) then
return emit_split()
end
end
if c.yarn ~= nil and o.yarn ~= nil and c.yarn == o.yarn + 1 and enabled("splits_yarn") then
return emit_split()
end
if c.checkpoint ~= nil and o.checkpoint ~= nil and c.checkpoint ~= o.checkpoint and c.checkpoint ~= 0 and enabled("splits_checkpoint") then
return emit_split()
end
end
if enabled("manySplits") and vars.currentRift == "none" then
if (tp_new or tp_any) and (enabled("manySplits_" .. tostring(c.chapter) .. "_" .. tostring(c.act) .. "_tp") or enabled("manySplits_" .. tostring(c.chapter) .. "_tp")) then
return emit_split()
end
if c.checkpoint ~= nil and o.checkpoint ~= nil and c.checkpoint ~= o.checkpoint and enabled("manySplits_" .. tostring(c.chapter) .. "_" .. tostring(c.act) .. "_cp" .. tostring(c.checkpoint)) then
return emit_split()
end
if vars.posSplitKey ~= 0 and enabled("manySplits_pos_" .. tostring(vars.posSplitKey)) then
local p = posSplitsDict[vars.posSplitKey]
if p ~= nil and all_position_values_available(c) and pos_match(c.x, c.y, c.z, p) then
return emit_split()
end
end
if vars.splitInLoadScreen and c.gameTimerIsPaused == 1 and o.gameTimerIsPaused == 0 then
return emit_split()
end
if c.actTimerIsVisible == 1 and o.actTimerIsVisible == 0 and not enabled("settings_ILMode")
and (enabled("manySplits_" .. tostring(c.chapter) .. "_" .. tostring(c.act) .. "_entry") or enabled("manySplits_" .. tostring(c.chapter) .. "_entry"))
then
return emit_split()
end
if c.gameTimerIsPaused == 1 and o.gameTimerIsPaused == 0 and enabled("manySplits_" .. tostring(c.chapter) .. "_" .. tostring(c.act) .. "_cp" .. tostring(c.checkpoint) .. "_pause") then
return emit_split()
end
if c.gameTimerIsPaused ~= o.gameTimerIsPaused and all_position_values_available(c) and should_split_at_this_pos_pause(c.chapter, c.x, c.y, c.z) then
return emit_split()
end
end
if enabled("manySplits") and vars.currentRift ~= "none" then
if (tp_new or tp_any) and enabled(vars.currentRift .. "_tp") then
return emit_split()
end
if c.checkpoint ~= nil and o.checkpoint ~= nil and c.checkpoint > o.checkpoint and enabled(vars.currentRift .. "_cp") then
return emit_split()
end
if vars.justEnteredRift and enabled(vars.currentRift .. "_entry") and not enabled("settings_ILMode") and elapsed_ms() > 3000 then
return emit_split()
end
end
return false
end
function reset()
local c = vars.current
local o = vars.old
if c.timerState == nil or o.timerState == nil then
return false
end
if c.timerState == 0 and o.timerState == 1 then
return true
end
if enabled("settings_ILMode") then
if c.actTimerIsVisible == 0 and o.actTimerIsVisible == 1 then
return true
end
if c.realActTime ~= nil and o.realActTime ~= nil and c.realActTime < o.realActTime and c.realActTime == 0 then
return true
end
end
return false
end
function isLoading()
return true
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment