<?xml version="1.0" encoding="utf-8"?>
<CheatTable CheatEngineTableVersion="52">
  <CheatEntries>
    <CheatEntry>
      <ID>0</ID>
      <Description>"Subnautica 2 - Trainer (F1-F11)"</Description>
      <Options moHideChildren="1" moManualExpandCollapse="1" moDeactivateChildrenAsWell="1"/>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]
{$lua}
--[[
  Subnautica 2 - Cheat Engine Lua Trainer (Self-Adapting)
  Process: Subnautica2-Win64-Test.exe (Unreal Engine 5 + Gameplay Ability System)

  Pointer Chain:
    GWorld -&gt; UWorld -&gt; PersistentLevel -&gt; Actors[]
      -&gt; BP_SN2PlayerController_C -&gt; Character
      -&gt; UWEAbilitySystemComponent -&gt; SpawnedAttributes[]
      -&gt; UWEHealthAttributeSet / UWESurvivalAttributeSet / ...

  All hardcoded offsets below are initial guesses. Each one is VALIDATED at startup
  and, if outdated (after a game update), is AUTOMATICALLY RE-DISCOVERED:
    - GWorld            : AOB scan on the instruction reading it
    - FNamePool         : scan for the "None/ByteProperty" block and the pointer to it
    - Object offsets    : pointer scan verified against Unreal class names
    - Attribute offsets : resolved via Unreal reflection (property name -&gt; offset)

  Usage: Activate the main Auto Assembler script in Cheat Engine (or paste in Cheat Table Lua Script)
]]

if syntaxcheck then return end

SN2 = SN2 or {}
local S = SN2
if S.stop then pcall(S.stop) end

-- ============================================================
-- 1. Initial Offset Guesses (2026-10-29 Build)
-- ============================================================
-- Candidate executable names (Experimental / Normal / Shipping / attached process)
S.MODULES = {
  'Subnautica2-Win64-Test.exe',
  'Subnautica2-Win64.exe',
  'Subnautica2-Win64-Shipping.exe',
  'Subnautica2.exe',
}
S.MODULE = S.MODULES[1]
S.off = {
  GWORLD      = 0xDC2E688,  -- module + offset
  FNAMEBLOCKS = 0xD9841D0,  -- module + offset (FNamePool.Blocks)
  WORLD_LEVEL = 0x30,
  WORLD_GS    = 0x1B0,      -- UWorld -&gt; GameState (BP_SN2GameState_C)
  GS_CONFIG   = 0x480,      -- SN2GameState -&gt; GameConfigComponent (UWEGameConfigComponent)
  GS_TAGS     = 0x370,      -- UWEGameStateBase -&gt; GlobalGameplayTags (FGameplayTagContainer)
  LEVEL_ACTORS= 0xA0,
  PC_PS       = 0x2F0,      -- PlayerController -&gt; PlayerState (BP_SN2PlayerState_C)
  PC_CHAR     = 0x338,
  PS_UNLOCK   = 0x488,      -- SN2PlayerState -&gt; UnlockPlayerStateComponent (SN2UnlockPlayerStateComponent)
  UNLOCK_LIST = 0xC8,       -- UnlockPlayerStateComponent -&gt; AllUnlockables (TArray&lt;TScriptInterface&gt;)
  CHAR_CMC    = 0x370,
  CHAR_ASC    = 0x820,
  CHAR_CRAFT  = 0x890,      -- Character -&gt; CraftingComponent (UWECraftingComponent)
  CRAFT_CUR   = 0xD8,       -- UWECraftingComponent -&gt; CurrentCrafterComponent (UWECrafterComponent)
  ASC_ABILS   = 0x530,      -- UWEAbilitySystemComponent -&gt; ActivatableAbilities.Items (TArray&lt;FGameplayAbilitySpec&gt;, stride 0xF0)
  ASC_SETS    = 0x1078,
}
-- UObject / Reflection layout (fixed for this UE5 version)
local UOBJ_CLASS, UOBJ_NAME = 0x10, 0x18
local USTRUCT_SUPER, USTRUCT_PROPS = 0x40, 0x50
local FFIELD_NEXT, FFIELD_NAME, FPROP_OFFSET = 0x18, 0x20, 0x44

S.PC_CLASS      = 'BP_SN2PlayerController_C'
S.GS_CLASS      = 'BP_SN2GameState_C'
S.GCC_CLASS     = 'UWEGameConfigComponent'
S.UNLOCK_CLASS  = 'SN2UnlockPlayerStateComponent'
S.ASC_CLASS     = 'UWEAbilitySystemComponent'
S.CMC_CLASS     = 'UWECharacterMovementComponent'
S.CRAFT_CLASS   = 'UWECraftingComponent'
S.CRAFTER_CLASS = 'UWECrafterComponent'

-- Fallback offsets on UWEGameConfigComponent (GameSettings @ +0xD8)
S.GCC_FALLBACK = {
  BiomodNoCost        = 0xDA, -- bool (1 byte)
  UnlockBioAbilities  = 0xDB, -- bool (1 byte)
  UnlockAdaptations   = 0xDC, -- bool (1 byte)
  UnlockBiomodSlots   = 0xDD, -- bool (1 byte)
  CraftingNoCost      = 0xE0, -- bool (1 byte)
  UnlockAllRecipes    = 0xE1, -- bool (1 byte)
  CraftingSpeedMult   = 0xE4, -- float (4 bytes, default 1.0)
  QuickProcessing     = 0xE8, -- bool (1 byte)
  UnlimitedPower      = 0xEC, -- bool (1 byte)
  UnlockScanFilters   = 0xED, -- bool (1 byte)
  UnlockDatabank      = 0xEE, -- bool (1 byte)
  UnlimitedBattery    = 0xF4, -- bool (1 byte)
}

-- Fallback offsets on UWECharacterMovementComponent (also resolved via reflection)
S.CMC_FALLBACK = {
  MovementMode        = 0x201,
  MaxWalkSpeed        = 0x288,
  MaxSwimSpeed        = 0x290,
  MaxAcceleration     = 0x29C,
  MaxWalkAcceleration = 0x1260,
  MaxSwimAcceleration = 0x1264,
}

-- Attribute groups: class name + used attributes
S.GROUPS = {
  Health     = { set='UWEHealthAttributeSet',
                 attrs={'Health','MaxHealth','DamageMultiplier','Radiation','Temperature','InternalTemperature'} },
  Survival   = { set='UWESurvivalAttributeSet',
                 attrs={'Oxygen','MaxOxygen','Food','MaxFood','Water','MaxWater'} },
  Movement   = { set='UWEMovementAttributeSet',
                 attrs={'MaxWalkSpeed','MaxSwimSpeed','DashOxygenCost'} },
  Mechanical = { set='UWEMechanicalAttributeSet',
                 attrs={'Energy','MaxEnergy','CrushDepth','ScanSpeedScalar','RepairSpeedScalar','EnergyConsumption'} },
}
-- Fallback offsets if reflection fails
S.FALLBACK_ATTR = {
  Health=0x50, MaxHealth=0x60, DamageMultiplier=0x70, Radiation=0x80, Temperature=0xE0, InternalTemperature=0xF0,
  Oxygen=0x48, MaxOxygen=0x58, Food=0x68, MaxFood=0x78, Water=0x98, MaxWater=0xA8,
  MaxWalkSpeed=0x48, MaxSwimSpeed=0x58, DashOxygenCost=0xB8,
  Energy=0x50, MaxEnergy=0x60, CrushDepth=0x80, ScanSpeedScalar=0x90, RepairSpeedScalar=0xA0, EnergyConsumption=0xB0,
}

-- ============================================================
-- 2. Helpers
-- ============================================================
local function valid(p) return p and p &gt; 0x10000 and p &lt; 0x7FFFFFFFFFFF and (p &amp; 7) == 0 end
-- Silent by default so the Lua Engine window does not pop up on activation/deactivation (only F8 prints to console)
local function log(fmt, ...)
  if S.verbose then print('[SN2] ' .. string.format(fmt, ...)) end
end
local function logConsole(fmt, ...)
  print('[SN2] ' .. string.format(fmt, ...))
end

local function qwordAOB(v)
  local b = {}
  for i = 0, 7 do b[#b+1] = string.format('%02X', (v &gt;&gt; (8*i)) &amp; 0xFF) end
  return table.concat(b, ' ')
end

function S.fname(idx)
  if not idx or idx &lt; 0 or not S.blocks then return nil end
  local blk = readQword(S.blocks + (idx &gt;&gt; 16) * 8)
  if not valid(blk) then return nil end
  local e = blk + (idx &amp; 0xFFFF) * 2
  local h = readSmallInteger(e)
  if not h then return nil end
  local len = h &gt;&gt; 6
  if len &lt;= 0 or len &gt; 250 then return nil end
  if (h &amp; 1) == 1 then return readString(e + 2, len * 2, true) end
  return readString(e + 2, len)
end

function S.objName(o)  if valid(o) then return S.fname(readInteger(o + UOBJ_NAME)) end end
function S.className(o)
  if not valid(o) then return nil end
  return S.objName(readQword(o + UOBJ_CLASS))
end

-- Scans obj[from..to] for a pointer to an object whose class satisfies test(className, ptr)
local function scanPtr(obj, from, to, test)
  for off = from, to, 8 do
    local p = readQword(obj + off)
    if valid(p) then
      local c = S.className(p)
      if c and test(c, p) then return off, p end
    end
  end
end

-- Reads a TArray&lt;UObject*&gt;: returns data, count if plausible
local function tarray(addr, maxN)
  local d, n = readQword(addr), readInteger(addr + 8)
  local cap = readInteger(addr + 12)
  if valid(d) and n and n &gt; 0 and n &lt;= (maxN or 100000) and cap and cap &gt;= n then return d, n end
end

-- ============================================================
-- 3. FNamePool &amp; GWorld
-- ============================================================
local function blocksOK(addr)
  local b0 = readQword(addr)
  return valid(b0) and readString(b0 + 2, 4) == 'None'
end

local function findFNameBlocks()
  log('Auto-scanning for FNamePool (~30 s)...')
  local hits = AOBScan('4E 6F 6E 65 ?? ?? 42 79 74 65 50 72 6F 70 65 72 74 79', '-X')
  if not hits then return nil end
  local list = {}
  for i = 0, hits.Count - 1 do list[#list+1] = tonumber('0x' .. hits[i]) - 2 end
  hits.destroy()
  local lo, hi = S.base, S.base + getModuleSize(S.MODULE)
  for _, blk in ipairs(list) do
    local refs = AOBScan(qwordAOB(blk), '-X', fsmAligned, '8')
    if refs then
      for i = 0, refs.Count - 1 do
        local a = tonumber('0x' .. refs[i])
        if a &gt;= lo and a &lt; hi and blocksOK(a) then refs.destroy(); return a end
      end
      refs.destroy()
    end
  end
end

local function worldOK(addr) return S.className(readQword(addr)) == 'World' end

local function findGWorld()
  log('Auto-scanning for GWorld...')
  local patterns = {
    '48 8B 1D ?? ?? ?? ?? 48 85 DB 74 ?? 41 B0 01',
    '48 8B 05 ?? ?? ?? ?? 48 3B C3 48 0F 44 C6',
  }
  for _, pat in ipairs(patterns) do
    -- Scan restricted to the game module (much faster than a global AOBScan)
    local ms = createMemScan()
    ms.firstScan(soExactValue, vtByteArray, rtRounded, pat, nil, S.base, S.base + getModuleSize(S.MODULE),
                 '+X', fsmNotAligned, '1', true, false, false, false)
    ms.waitTillDone()
    local fl = createFoundList(ms); fl.initialize()
    local found
    for i = 0, math.min(fl.Count, 50) - 1 do
      local a = tonumber('0x' .. fl.Address[i])
      local g = a + 7 + readInteger(a + 3, true)
      if worldOK(g) then found = g; break end
    end
    fl.destroy(); ms.destroy()
    if found then return found end
  end
end

-- ============================================================
-- 4. Object Offsets (Validated or Re-Discovered via Class Names)
-- ============================================================
local function resolveChain()
  local o = S.off
  local world = readQword(S.gworld)

  -- UWorld -&gt; PersistentLevel
  local level = readQword(world + o.WORLD_LEVEL)
  if S.objName(level) ~= 'PersistentLevel' then
    o.WORLD_LEVEL, level = scanPtr(world, 0x28, 0x400, function(c, p) return c == 'Level' and S.objName(p) == 'PersistentLevel' end)
    if not level then return nil, 'PersistentLevel not found' end
    log('WORLD_LEVEL -&gt; 0x%X', o.WORLD_LEVEL)
  end

  -- Level -&gt; Actors (TArray containing the PlayerController)
  local function findPC(off)
    local d, n = tarray(level + off, 50000)
    if not d then return nil end
    -- Quickly reject invalid TArrays: first 4 entries must be valid named UObjects
    for i = 0, math.min(n, 4) - 1 do
      if not S.className(readQword(d + i * 8)) then return nil end
    end
    for i = 0, n - 1 do
      local a = readQword(d + i * 8)
      if valid(a) and S.className(a) == S.PC_CLASS then return a end
    end
  end
  local pc = findPC(o.LEVEL_ACTORS)
  if not pc then
    for off = 0x28, 0x300, 8 do
      pc = findPC(off)
      if pc then o.LEVEL_ACTORS = off; log('LEVEL_ACTORS -&gt; 0x%X', off); break end
    end
    if not pc then return nil, 'PlayerController not found (not in game?)' end
  end

  -- PlayerController -&gt; Character (actor owning an ASC)
  local function hasASC(ch)
    local a = readQword(ch + o.CHAR_ASC)
    if S.className(a) == S.ASC_CLASS then return true end
    local off = scanPtr(ch, 0x28, 0x1800, function(c) return c == S.ASC_CLASS end)
    if off then o.CHAR_ASC = off; log('CHAR_ASC -&gt; 0x%X', off); return true end
  end
  local ch = readQword(pc + o.PC_CHAR)
  if not (valid(ch) and S.className(ch) and S.className(ch):find('Character') and hasASC(ch)) then
    o.PC_CHAR, ch = scanPtr(pc, 0x28, 0x800, function(c, p) return c:find('Character') and hasASC(p) end)
    if not ch then return nil, 'Player Character not found' end
    log('PC_CHAR -&gt; 0x%X', o.PC_CHAR)
  end

  local asc = readQword(ch + o.CHAR_ASC)
  if S.className(asc) ~= S.ASC_CLASS then hasASC(ch); asc = readQword(ch + o.CHAR_ASC) end

  -- Character -&gt; UWECharacterMovementComponent
  local cmc = readQword(ch + o.CHAR_CMC)
  if S.className(cmc) ~= S.CMC_CLASS then
    o.CHAR_CMC, cmc = scanPtr(ch, 0x28, 0x800, function(c) return c == S.CMC_CLASS end)
    if cmc then log('CHAR_CMC -&gt; 0x%X', o.CHAR_CMC) end
  end

  -- Character -&gt; UWECraftingComponent
  local craftComp = readQword(ch + o.CHAR_CRAFT)
  if S.className(craftComp) ~= S.CRAFT_CLASS then
    local off, p = scanPtr(ch, 0x400, 0x1000, function(c) return c == S.CRAFT_CLASS end)
    if off then o.CHAR_CRAFT, craftComp = off, p; log('CHAR_CRAFT -&gt; 0x%X', off) end
  end

  -- PlayerController -&gt; PlayerState -&gt; UnlockPlayerStateComponent
  local ps = readQword(pc + o.PC_PS)
  if not (valid(ps) and S.className(ps) and S.className(ps):find('PlayerState')) then
    local off, p = scanPtr(pc, 0x200, 0x500, function(c) return c:find('PlayerState') end)
    if off then o.PC_PS, ps = off, p; log('PC_PS -&gt; 0x%X', off) end
  end
  local unlockComp = valid(ps) and readQword(ps + o.PS_UNLOCK)
  if S.className(unlockComp) ~= S.UNLOCK_CLASS and valid(ps) then
    local off, p = scanPtr(ps, 0x200, 0x700, function(c) return c == S.UNLOCK_CLASS end)
    if off then o.PS_UNLOCK, unlockComp = off, p; log('PS_UNLOCK -&gt; 0x%X', off) end
  end

  -- ASC -&gt; SpawnedAttributes (TArray of *AttributeSet objects)
  local function setsAt(off)
    local d, n = tarray(asc + off, 32)
    if not d then return nil end
    local c = S.className(readQword(d))
    if c and c:find('AttributeSet') then return d, n end
  end
  local d, n = setsAt(o.ASC_SETS)
  if not d then
    for off = 0x28, 0x2000, 8 do
      d, n = setsAt(off)
      if d then o.ASC_SETS = off; log('ASC_SETS -&gt; 0x%X', off); break end
    end
    if not d then return nil, 'AttributeSets not found' end
  end

  local sets = {}
  for i = 0, n - 1 do
    local s = readQword(d + i * 8)
    local c = S.className(s)
    if c then sets[c] = s end
  end

  -- UWorld -&gt; GameState -&gt; GameConfigComponent
  local gs = readQword(world + o.WORLD_GS)
  if not (valid(gs) and S.className(gs) and S.className(gs):find('GameState')) then
    local off, p = scanPtr(world, 0x100, 0x300, function(c) return c:find('GameState') end)
    if off then o.WORLD_GS, gs = off, p; log('WORLD_GS -&gt; 0x%X', off) end
  end
  local gcc = valid(gs) and readQword(gs + o.GS_CONFIG)
  if S.className(gcc) ~= S.GCC_CLASS and valid(gs) then
    local off, p = scanPtr(gs, 0x200, 0x600, function(c) return c == S.GCC_CLASS end)
    if off then o.GS_CONFIG, gcc = off, p; log('GS_CONFIG -&gt; 0x%X', off) end
  end

  return {
    world = world, level = level, gs = gs, gcc = gcc,
    pc = pc, ps = ps, unlockComp = unlockComp,
    character = ch, cmc = cmc, craftComp = craftComp,
    asc = asc, sets = sets
  }
end

-- ============================================================
-- 5. Attribute Offsets via Unreal Reflection
-- ============================================================
local function reflectProps(obj)
  local map, cls, guard = {}, readQword(obj + UOBJ_CLASS), 0
  while valid(cls) and guard &lt; 10 do
    local f, g = readQword(cls + USTRUCT_PROPS), 0
    while valid(f) and g &lt; 300 do
      local n = S.fname(readInteger(f + FFIELD_NAME))
      local off = readInteger(f + FPROP_OFFSET)
      if n and off and off &gt;= 0x28 and off &lt; 0x2000 then map[n] = off end
      f, g = readQword(f + FFIELD_NEXT), g + 1
    end
    cls, guard = readQword(cls + USTRUCT_SUPER), guard + 1
  end
  return map
end

S.attrOff = {}
S.cmcOff  = {}
local function resolveAttrOffsets(sets, cmc)
  local nRefl, nFb = 0, 0
  for g, info in pairs(S.GROUPS) do
    local obj = sets[info.set]
    local map = obj and reflectProps(obj) or {}
    S.attrOff[g] = {}
    for _, a in ipairs(info.attrs) do
      if map[a] then S.attrOff[g][a] = map[a]; nRefl = nRefl + 1
      else S.attrOff[g][a] = S.FALLBACK_ATTR[a]; nFb = nFb + 1 end
    end
  end
  local cmcMap = valid(cmc) and reflectProps(cmc) or {}
  for k, fb in pairs(S.CMC_FALLBACK) do
    S.cmcOff[k] = cmcMap[k] or fb
  end
  log('Attributes: %d resolved via reflection, %d via fallback offsets', nRefl, nFb)
end

-- ============================================================
-- 6. Initialization &amp; Cache
-- ============================================================
function S.init()
  S.base = nil
  if process and process ~= '' then
    local b = getAddressSafe(process)
    if b and b ~= 0 then S.MODULE = process; S.base = b end
  end
  if not S.base then
    for _, m in ipairs(S.MODULES) do
      local b = getAddressSafe(m)
      if b and b ~= 0 then S.MODULE = m; S.base = b; break end
    end
  end
  if not S.base or S.base == 0 then error('Game module not found: attach Cheat Engine to the game first') end
  log('Detected module: %s (base=0x%X)', S.MODULE, S.base)

  S.blocks = S.base + S.off.FNAMEBLOCKS
  if not blocksOK(S.blocks) then
    S.blocks = findFNameBlocks()
    if not S.blocks then error('FNamePool not found') end
    S.off.FNAMEBLOCKS = S.blocks - S.base
    log('FNAMEBLOCKS -&gt; module+0x%X', S.off.FNAMEBLOCKS)
  end

  S.gworld = S.base + S.off.GWORLD
  if not worldOK(S.gworld) then
    S.gworld = findGWorld()
    if not S.gworld then error('GWorld not found') end
    S.off.GWORLD = S.gworld - S.base
    log('GWORLD -&gt; module+0x%X', S.off.GWORLD)
  end
  registerSymbol('SN2_GWorld', S.gworld, true)
  log('Init OK  GWorld=0x%X  FNameBlocks=0x%X', S.gworld, S.blocks)
end

S.cache = nil
function S.refresh()
  local r, err = resolveChain()
  if not r then S.cache = nil; return false, err end
  S.cache = r
  if not S.attrResolved then resolveAttrOffsets(r.sets, r.cmc); S.attrResolved = true end
  return true
end

local function setAddr(group)
  local cls = S.GROUPS[group].set
  local a = S.cache and S.cache.sets[cls]
  if not a or S.className(a) ~= cls then          -- respawn, level load, zone transition...
    if not S.refresh() then return nil end
    a = S.cache.sets[cls]
  end
  return a
end

-- Safe memory writes (only write when the value actually differs)
local function writeByteIf(addr, val)
  if readBytes(addr, 1) ~= val then writeBytes(addr, val) end
end
local function writeIntIf(addr, val)
  if readInteger(addr) ~= val then writeInteger(addr, val) end
end
local function writeFloatIf(addr, val)
  local cur = readFloat(addr)
  if not cur or math.abs(cur - val) &gt; 0.001 then writeFloat(addr, val) end
end

function S.get(group, attr)
  local a = setAddr(group); if not a then return nil end
  return readFloat(a + S.attrOff[group][attr] + 0xC)
end

function S.set(group, attr, value)
  local a = setAddr(group); if not a then return false end
  local off = S.attrOff[group][attr]
  writeFloatIf(a + off + 0x8, value)   -- BaseValue
  writeFloatIf(a + off + 0xC, value)   -- CurrentValue
  return true
end

-- Prints resolved offsets to update S.off after a game patch
function S.dumpOffsets()
  for k, v in pairs(S.off) do logConsole('%-12s = 0x%X', k, v) end
end

-- ============================================================
-- 7. Survival &amp; Movement Cheats
-- ============================================================
local function fill(group, attr, maxAttr)
  local m, v = S.get(group, maxAttr), S.get(group, attr)
  if m and v and m &gt; 0 and v &lt; m then S.set(group, attr, m) end
end

S.cheats = {
  godmode     = { name='Infinite Health',    on=false, tick=function() fill('Health','Health','MaxHealth') end },
  oxygen      = { name='Infinite Oxygen',    on=false, tick=function() fill('Survival','Oxygen','MaxOxygen') end },
  food        = { name='Infinite Food',      on=false, tick=function() fill('Survival','Food','MaxFood') end },
  water       = { name='Infinite Water',     on=false, tick=function() fill('Survival','Water','MaxWater') end },
  energy      = { name='Infinite Energy',    on=false, tick=function() fill('Mechanical','Energy','MaxEnergy') end },
  noradiation = { name='No Radiation',       on=false, tick=function() S.set('Health','Radiation',0) end },
  temperature = { name='Stable Temperature', on=false, tick=function()
                    S.set('Health','Temperature',20); S.set('Health','InternalTemperature',20) end },
}

S.defaults  = S.defaults or {}
S.speedMult = S.speedMult or 1.0
S.SPEED_MIN = 1.0
S.SPEED_MAX = 10.0   -- x10 (3500 u/s): above this threshold, UE5 collision tunneling may occur
S.SPEED_STEP = 1.0

function S.toggle(id)
  local c = S.cheats[id]; if not c then log('Unknown cheat: %s', tostring(id)); return end
  c.on = not c.on
  log('%s: %s', c.name, c.on and 'ON' or 'OFF')
  if c.on then beep() end
  if S.syncUI then pcall(S.syncUI) end
end

function S.applySpeed()
  local mult = S.speedMult or 1.0
  local swim = (S.defaults.swim or 350) * mult
  local walk = (S.defaults.walk or 350) * mult
  S.set('Movement','MaxSwimSpeed', swim)
  S.set('Movement','MaxWalkSpeed', walk)
  local cmc = S.cache and S.cache.cmc
  if valid(cmc) and S.className(cmc) == S.CMC_CLASS then
    local c = S.cmcOff
    writeFloatIf(cmc + c.MaxSwimSpeed, swim)
    writeFloatIf(cmc + c.MaxWalkSpeed, walk)
    writeFloatIf(cmc + c.MaxSwimAcceleration, (S.defaults.swimAccel or 1024) * mult)
    writeFloatIf(cmc + c.MaxWalkAcceleration, (S.defaults.walkAccel or 2048) * mult)
    writeFloatIf(cmc + c.MaxAcceleration,     (S.defaults.accel or 1024) * mult)
  end
end

function S.speed(mult)
  if not S.cache or not valid(S.cache.cmc) then S.refresh() end
  S.defaults.swim = S.defaults.swim or S.get('Movement','MaxSwimSpeed')
  S.defaults.walk = S.defaults.walk or S.get('Movement','MaxWalkSpeed')
  if not S.defaults.swim then log('Player not found'); return end
  if valid(S.cache and S.cache.cmc) and not S.defaults.swimAccel then
    local cmc, c = S.cache.cmc, S.cmcOff
    S.defaults.swimAccel = readFloat(cmc + c.MaxSwimAcceleration) or 1024
    S.defaults.walkAccel = readFloat(cmc + c.MaxWalkAcceleration) or 2048
    S.defaults.accel     = readFloat(cmc + c.MaxAcceleration) or 1024
  end
  mult = math.max(S.SPEED_MIN, math.min(S.SPEED_MAX, mult))
  S.speedMult = mult
  S.applySpeed()
  log('Speed x%.1f (Swim=%.0f, Walk=%.0f)', mult, S.defaults.swim * mult, S.defaults.walk * mult)
  if S.syncUI then pcall(S.syncUI) end
end

function S.speedStep(delta)
  S.speed((S.speedMult or 1.0) + delta)
end

function S.crushDepth(m) S.set('Mechanical','CrushDepth', m); log('CrushDepth = %d', m) end
function S.maxOxygen(v)  S.set('Survival','MaxOxygen', v); S.set('Survival','Oxygen', v); log('MaxOxygen = %d', v) end

-- ============================================================
-- 7b. Crafting &amp; Unlock (Fabricator, Biomod, Processor, Builder)
-- ============================================================
S.craftMode    = S.craftMode or false
S.origRecipes  = S.origRecipes or {}
S.origUnlocks  = S.origUnlocks or {}
S.origCrafters = S.origCrafters or {}

local function patchRecipe(r, enable)
  if not valid(r) or S.className(r) ~= 'UWECraftingRecipe' then return end
  local orig = S.origRecipes[r]
  if not orig then
    local st = readBytes(r + 0xF0, 1) or 2
    local tm = readFloat(r + 0x108) or 2.0
    orig = { state = st, time = (tm &gt; 0.01) and tm or 2.0 }
    S.origRecipes[r] = orig
  end
  if enable then
    writeByteIf(r + 0xF0, 1)      -- DefaultRecipeState = 1 (Unlocked)
    writeFloatIf(r + 0x108, 0.0)  -- CraftingTime = 0.0s (triggers native instant craft)
  else
    writeByteIf(r + 0xF0, orig.state)
    writeFloatIf(r + 0x108, orig.time)
  end
end

local UNLOCK_STATE_OFF = {
  SN2BuilderConstructActionData        = 0x128,
  SN2ItemBrushActionData               = 0x128,
  SN2BaseScannerStationFilterDataAsset = 0xC8,
  UWEBioScanData                       = 0xB0,
  SN2AxumGlyphDataAsset                = 0xA0,
}

local function patchCrafter(comp, enable)
  if not valid(comp) or S.className(comp) ~= S.CRAFTER_CLASS then return end
  local orig = S.origCrafters[comp]
  if not orig then
    local n  = readInteger(comp + 0x118) or 0
    local dt = readFloat(comp + 0x19C) or 1.5
    orig = { allowedNum = n, defaultTime = (dt &gt; 0.05) and dt or 1.5 }
    S.origCrafters[comp] = orig
  end
  if enable then
    -- Clear AllowedRecipesOverride count (e.g. removes the 24-recipe restriction on the Lifepod Fabricator)
    writeIntIf(comp + 0x118, 0)
    writeFloatIf(comp + 0x19C, 0.0)
  else
    writeIntIf(comp + 0x118, orig.allowedNum)
    writeFloatIf(comp + 0x19C, orig.defaultTime)
  end
end

function S.setCraftingCheats(enable, fullScan)
  if not S.cache or S.className(S.cache.gcc) ~= S.GCC_CLASS then S.refresh() end
  local gcc = S.cache and S.cache.gcc
  if S.className(gcc) ~= S.GCC_CLASS then return false end
  local g = S.GCC_FALLBACK
  local b = enable and 1 or 0
  -- CraftingSettings: NoCost + UnlockAllRecipes + Speed x25 + QuickProcessing
  writeByteIf(gcc + g.CraftingNoCost,     b)
  writeByteIf(gcc + g.UnlockAllRecipes,   b)
  writeFloatIf(gcc + g.CraftingSpeedMult, (enable or S.toolsMode) and 25.0 or 1.0)
  writeByteIf(gcc + g.QuickProcessing,    b)
  -- BiomodSettings: NoCost + UnlockAllBioAbilities + Adaptations + BiomodSlots
  writeByteIf(gcc + g.BiomodNoCost,       b)
  writeByteIf(gcc + g.UnlockBioAbilities, b)
  writeByteIf(gcc + g.UnlockAdaptations,  b)
  writeByteIf(gcc + g.UnlockBiomodSlots,  b)
  -- Power &amp; Batteries (Fabricator / tools require no power)
  writeByteIf(gcc + g.UnlimitedPower,   (enable or S.toolsMode) and 1 or 0)
  writeByteIf(gcc + g.UnlimitedBattery, (enable or S.toolsMode) and 1 or 0)

  -- Crafter currently opened by the player (UWECraftingComponent.CurrentCrafterComponent)
  local craftComp = S.cache and S.cache.craftComp
  if S.className(craftComp) == S.CRAFT_CLASS then
    patchCrafter(readQword(craftComp + S.off.CRAFT_CUR), enable)
  end

  if fullScan then
    -- 1) All recipes &amp; buildables via PlayerState.UnlockPlayerStateComponent.AllUnlockables
    local uc = S.cache and S.cache.unlockComp
    if S.className(uc) == S.UNLOCK_CLASS then
      local data = readQword(uc + S.off.UNLOCK_LIST)
      local num  = readInteger(uc + S.off.UNLOCK_LIST + 8)
      if valid(data) and num and num &gt; 0 and num &lt; 5000 then
        for i = 0, num - 1 do
          local obj = readQword(data + i * 16)
          local cls = S.className(obj)
          if cls == 'UWECraftingRecipe' then
            patchRecipe(obj, enable)
          elseif cls then
            local uOff = UNLOCK_STATE_OFF[cls]
            if uOff then
              if not S.origUnlocks[obj] then
                S.origUnlocks[obj] = { off = uOff, state = readBytes(obj + uOff, 1) or 2 }
              end
              writeByteIf(obj + uOff, enable and 1 or S.origUnlocks[obj].state)
            end
            if cls == 'SN2BuilderConstructActionData' then
              patchRecipe(readQword(obj + 0x318), enable)
            end
          end
        end
      end
    end

    -- 2) All Fabricators / Crafters currently loaded in the level
    local level = S.cache and S.cache.level
    if S.className(level) == 'Level' then
      local d, n = tarray(level + S.off.LEVEL_ACTORS, 50000)
      if d then
        for i = 0, n - 1 do
          local a = readQword(d + i * 8)
          local c = S.className(a)
          if c and (c:find('Fabricator') or c:find('Crafter')) then
            patchCrafter(readQword(a + 0x318), enable)
          end
        end
      end
    end
  end
  return true
end

function S.toggleCrafting()
  S.craftMode = not S.craftMode
  S.setCraftingCheats(S.craftMode, true)
  log('Free Craft &amp; Unlock All Recipes: %s', S.craftMode and 'ON' or 'OFF')
  if S.craftMode then beep() end
  if S.syncUI then pcall(S.syncUI) end
end

-- ============================================================
-- 7c. Tools: Fast Scan + Fast Build/Repair + Infinite Battery (F10)
-- ============================================================
S.toolsMode = S.toolsMode or false

function S.setToolsCheats(enable)
  if not S.cache or S.className(S.cache.asc) ~= S.ASC_CLASS then S.refresh() end
  -- 1) Fast Scan (x15 = ~0.13s, gives 6-8 frames to the D3D12 GameplayCue.Tools.Scanner.Overlay shader)
  --    &amp; Fast Repair (x20) + Zero Energy Consumption
  S.set('Mechanical', 'ScanSpeedScalar',   enable and 15.0 or 1.0)
  S.set('Mechanical', 'RepairSpeedScalar', enable and 20.0 or 1.0)
  S.set('Mechanical', 'EnergyConsumption', 0.0)
  if enable then
    fill('Mechanical', 'Energy', 'MaxEnergy')
    S.set('Movement', 'DashOxygenCost', 0.0)
  end

  -- 2) Fast Construction / Deconstruction with the Builder (x25 @ gcc + 0xE4)
  --    + Native Unlimited Battery &amp; Power (gcc + 0xF4 / +0xEC, without touching inventory actors)
  local gcc = S.cache and S.cache.gcc
  if S.className(gcc) == S.GCC_CLASS then
    local g = S.GCC_FALLBACK
    writeFloatIf(gcc + g.CraftingSpeedMult, (enable or S.craftMode) and 25.0 or 1.0)
    writeByteIf(gcc + g.UnlimitedBattery,   (enable or S.craftMode) and 1 or 0)
    writeByteIf(gcc + g.UnlimitedPower,     (enable or S.craftMode) and 1 or 0)
  end
  return true
end

function S.toggleTools()
  S.toolsMode = not S.toolsMode
  S.setToolsCheats(S.toolsMode)
  log('Fast Scan / Build / Repair &amp; Infinite Battery: %s', S.toolsMode and 'ON' or 'OFF')
  if S.toolsMode then beep() end
  if S.syncUI then pcall(S.syncUI) end
end

-- ============================================================
-- 7d. Infinite Air Jump / Multi-Jump (F11)
-- ============================================================
S.jumpMode  = S.jumpMode or false
S.origJump  = S.origJump or {}

local function patchJumpAbility(ab, allowMidAir)
  if S.className(ab) ~= 'GA_Jump_C' then return end
  local orig = S.origJump[ab]
  if not orig then
    local rn = readInteger(ab + 0x230)
    local pn = readInteger(ab + 0x240)
    local cd = readFloat(ab + 0x3C8)
    orig = {
      reqNum    = (rn and rn &gt; 0) and rn or 1,
      parentNum = (pn and pn &gt; 0) and pn or 2,
      cooldown  = (cd and cd &gt; 0.05) and cd or 0.5,
    }
    S.origJump[ab] = orig
  end
  if allowMidAir then
    -- Out of water: clear Movement.Land.Walking requirement to allow mid-air jumping (0.15s anti-spam cooldown)
    writeIntIf(ab + 0x230, 0)
    writeIntIf(ab + 0x240, 0)
    writeFloatIf(ab + 0x3C8, 0.15)
  else
    -- Underwater or disabled: restore Movement.Land.Walking so Spacebar (Ascend) does not spam GA_Jump_C
    writeIntIf(ab + 0x230, orig.reqNum)
    writeIntIf(ab + 0x240, orig.parentNum)
    writeFloatIf(ab + 0x3C8, orig.cooldown)
  end
end

function S.setInfiniteJump(enable)
  if not S.cache or S.className(S.cache.asc) ~= S.ASC_CLASS then S.refresh() end
  local ch  = S.cache and S.cache.character
  local cmc = S.cache and S.cache.cmc
  local asc = S.cache and S.cache.asc
  if not (valid(ch) and S.className(asc) == S.ASC_CLASS) then return false end

  if not S.origJump.maxCount then
    local mc = readInteger(ch + 0x4A4)
    S.origJump.maxCount = (mc and mc &gt; 0 and mc &lt; 100) and mc or 1
  end

  -- Check if the player is out of water (MovementMode: 1 = Walking, 3 = Falling, 4 = Swimming)
  local moveMode = (S.className(cmc) == S.CMC_CLASS and S.cmcOff.MovementMode)
                   and readBytes(cmc + S.cmcOff.MovementMode, 1) or 1
  local allowMidAir = enable and (moveMode == 1 or moveMode == 3)

  if allowMidAir then
    writeIntIf(ch + 0x4A4, 999999) -- JumpMaxCount
    writeIntIf(ch + 0x4A8, 0)      -- JumpCurrentCount
    writeIntIf(ch + 0x4AC, 0)      -- JumpCurrentCountPreJump
  else
    writeIntIf(ch + 0x4A4, S.origJump.maxCount or 1)
  end

  local data = readQword(asc + S.off.ASC_ABILS)
  local num  = readInteger(asc + S.off.ASC_ABILS + 8)
  if valid(data) and num and num &gt; 0 and num &lt;= 200 then
    for i = 0, num - 1 do
      local spec = data + i * 0xF0
      local cdo  = readQword(spec + 0x10)
      if S.className(cdo) == 'GA_Jump_C' then
        patchJumpAbility(cdo, allowMidAir)
        local instArr = readQword(spec + 0x78)
        local instNum = readInteger(spec + 0x80)
        if valid(instArr) and instNum and instNum &gt; 0 and instNum &lt;= 16 then
          for j = 0, instNum - 1 do
            patchJumpAbility(readQword(instArr + j * 8), allowMidAir)
          end
        end
        break
      end
    end
  end
  return true
end

function S.toggleJump()
  S.jumpMode = not S.jumpMode
  S.setInfiniteJump(S.jumpMode)
  log('Infinite Air Jump (Multi-Jump): %s', S.jumpMode and 'ON' or 'OFF')
  if S.jumpMode then beep() end
  if S.syncUI then pcall(S.syncUI) end
end

function S.status()
  local ok, err = S.refresh()
  if not ok then logConsole('Player not found: %s', err or '?'); return end
  logConsole('HP %.0f/%.0f | O2 %.0f/%.0f | Food %.0f/%.0f | Water %.0f/%.0f | Swim %.0f (x%.1f)',
    S.get('Health','Health'), S.get('Health','MaxHealth'),
    S.get('Survival','Oxygen'), S.get('Survival','MaxOxygen'),
    S.get('Survival','Food'), S.get('Survival','MaxFood'),
    S.get('Survival','Water'), S.get('Survival','MaxWater'),
    S.get('Movement','MaxSwimSpeed'), S.speedMult or 1.0)
end

-- ============================================================
-- 8. Cheat Engine UI (Child Checkboxes F1-F11) &amp; Main Loop
-- ============================================================
S.UI_ITEMS = {
  { id = 'f1',  desc = 'F1 - Infinite Health',                            kind = 'toggle' },
  { id = 'f2',  desc = 'F2 - Infinite Oxygen',                            kind = 'toggle' },
  { id = 'f3',  desc = 'F3 - Infinite Food &amp; Water',                      kind = 'toggle' },
  { id = 'f4',  desc = 'F4 - Infinite Energy',                            kind = 'toggle' },
  { id = 'f5',  desc = 'F5 - No Radiation &amp; Stable Temperature',          kind = 'toggle' },
  { id = 'f6',  desc = 'F6 - Increase Speed (+1.0x) [x1.0]',              kind = 'action' },
  { id = 'f7',  desc = 'F7 - Decrease Speed (-1.0x)',                     kind = 'action' },
  { id = 'f8',  desc = 'F8 - Print Player Status (Lua Console)',          kind = 'action' },
  { id = 'f9',  desc = 'F9 - Free Craft &amp; Unlock All Recipes',            kind = 'toggle' },
  { id = 'f10', desc = 'F10 - Fast Scan / Build / Repair &amp; Infinite Battery', kind = 'toggle' },
  { id = 'f11', desc = 'F11 - Infinite Air Jump (Multi-Jump)',            kind = 'toggle' },
}

function S.getUIState(id)
  if id == 'f1'  then return S.cheats.godmode.on end
  if id == 'f2'  then return S.cheats.oxygen.on end
  if id == 'f3'  then return S.cheats.food.on end
  if id == 'f4'  then return S.cheats.energy.on end
  if id == 'f5'  then return S.cheats.noradiation.on end
  if id == 'f9'  then return S.craftMode end
  if id == 'f10' then return S.toolsMode end
  if id == 'f11' then return S.jumpMode end
  return false
end

function S.onChildUI(id, enable)
  if S.syncingUI then return end
  if id == 'f1' then
    if S.cheats.godmode.on ~= enable then S.toggle('godmode') end
  elseif id == 'f2' then
    if S.cheats.oxygen.on ~= enable then S.toggle('oxygen') end
  elseif id == 'f3' then
    if S.cheats.food.on ~= enable then S.toggle('food'); S.toggle('water') end
  elseif id == 'f4' then
    if S.cheats.energy.on ~= enable then S.toggle('energy') end
  elseif id == 'f5' then
    if S.cheats.noradiation.on ~= enable then S.toggle('noradiation'); S.toggle('temperature') end
  elseif id == 'f6' and enable then
    S.speedStep(S.SPEED_STEP)
  elseif id == 'f7' and enable then
    S.speedStep(-S.SPEED_STEP)
  elseif id == 'f8' and enable then
    S.status()
  elseif id == 'f9' then
    if S.craftMode ~= enable then S.toggleCrafting() end
  elseif id == 'f10' then
    if S.toolsMode ~= enable then S.toggleTools() end
  elseif id == 'f11' then
    if S.jumpMode ~= enable then S.toggleJump() end
  end
  S.syncUI()
end

function S.findParentRecord(passedRec)
  if passedRec then return passedRec end
  local al = getAddressList()
  for i = 0, al.Count - 1 do
    local mr = al.getMemoryRecord(i)
    if mr and mr.Type == vtAutoAssembler and mr.Script and mr.Script:find('SN2 = SN2 or {}', 1, true) then
      return mr
    end
  end
  return nil
end

function S.buildUI(passedRec)
  local al = getAddressList()
  local parent = S.findParentRecord(passedRec)
  if not parent then return end
  S.parentRec = parent
  if parent.Description == 'Auto Assemble script' then
    parent.Description = 'Subnautica 2 - Trainer (F1-F11)'
  end
  parent.Options = '[moHideChildren,moDeactivateChildrenAsWell,moManualExpandCollapse]'

  S.uiRecords = {}
  local existing = {}
  for i = 0, parent.Count - 1 do
    local ch = parent.Child[i]
    local key = ch and ch.Description and ch.Description:match('^(F%d+)')
    if key then existing[key:lower()] = ch end
  end

  for _, item in ipairs(S.UI_ITEMS) do
    local mr = existing[item.id]
    if not mr then
      mr = al.createMemoryRecord()
      mr.appendToEntry(parent)
    end
    mr.Description = item.desc
    mr.Type = vtAutoAssembler
    if item.kind == 'action' then
      mr.Script = string.format(
        "[ENABLE]\n{$lua}\nif syntaxcheck then return end\nif SN2 and not SN2.syncingUI then\n  SN2.onChildUI('%s', true)\n  local t = createTimer(nil, false); t.Interval = 30\n  t.OnTimer = function(tm) tm.destroy(); if SN2 then SN2.syncingUI = true; memrec.Active = false; SN2.syncingUI = false end end\n  t.Enabled = true\nend\n{$asm}\n[DISABLE]\n{$lua}\nif syntaxcheck then return end\n{$asm}\n",
        item.id
      )
    else
      mr.Script = string.format(
        "[ENABLE]\n{$lua}\nif syntaxcheck then return end\nif SN2 and not SN2.syncingUI then SN2.onChildUI('%s', true) end\n{$asm}\n[DISABLE]\n{$lua}\nif syntaxcheck then return end\nif SN2 and not SN2.syncingUI then SN2.onChildUI('%s', false) end\n{$asm}\n",
        item.id, item.id
      )
    end
    S.uiRecords[item.id] = mr
  end

  -- Automatically expand child records once parent activation finishes
  local t = createTimer(nil, false)
  t.Interval = 30
  t.OnTimer = function(tm)
    tm.destroy()
    if S.parentRec then pcall(function() S.parentRec.Collapsed = false end) end
    S.syncUI()
  end
  t.Enabled = true
end

function S.syncUI()
  if not S.uiRecords or S.syncingUI then return end
  S.syncingUI = true
  pcall(function()
    local defColor = (S.parentRec and S.parentRec.Color) or -2147483640
    for _, item in ipairs(S.UI_ITEMS) do
      local mr = S.uiRecords[item.id]
      if mr then
        if item.id == 'f6' then
          mr.Description = string.format('F6 - Increase Speed (+1.0x) [x%.1f]', S.speedMult or 1.0)
          mr.Color = (S.speedMult and S.speedMult &gt; 1.0) and 0x008000 or defColor
        elseif item.kind == 'toggle' then
          local st = S.getUIState(item.id)
          if mr.Active ~= st then mr.Active = st end
          mr.Color = st and 0x008000 or defColor
        else
          mr.Color = defColor
        end
      end
    end
  end)
  S.syncingUI = false
end

-- Compact View Mode (hides Cheat Engine scanner panels when active)
function cycleFullCompact(sender, force)
  local state = not (compactmenuitem.Caption == 'Compact View Mode')
  if force ~= nil then state = not force end
  compactmenuitem.Caption = state and 'Compact View Mode' or 'Full View Mode'
  getMainForm().Splitter1.Visible = state
  getMainForm().Panel4.Visible    = state
  getMainForm().Panel5.Visible    = state
end

function addCompactMenu()
  if compactmenualreadyexists then return end
  local parent = getMainForm().Menu.Items
  compactmenuitem = createMenuItem(parent); parent.add(compactmenuitem)
  compactmenuitem.Caption = 'Compact View Mode'
  compactmenuitem.OnClick = cycleFullCompact
  compactmenualreadyexists = 'yes'
end

function S.start(passedRec)
  pcall(addCompactMenu)
  pcall(cycleFullCompact, nil, true)
  S.init()
  S.attrResolved = false
  S.refresh()
  pcall(S.buildUI, passedRec)

  S.timer = createTimer(nil, false)
  S.timer.Interval = 100
  S.timer.OnTimer = function()
    for _, c in pairs(S.cheats) do if c.on then pcall(c.tick) end end
    if S.speedMult and S.speedMult &gt; 1.0 then pcall(S.applySpeed) end
    if S.craftMode then pcall(S.setCraftingCheats, true) end
    if S.toolsMode then pcall(S.setToolsCheats, true) end
    if S.jumpMode  then pcall(S.setInfiniteJump, true) end
  end
  S.timer.Enabled = true

  S.hotkeys = {
    createHotkey(function() S.toggle('godmode') end, VK_F1),
    createHotkey(function() S.toggle('oxygen') end,  VK_F2),
    createHotkey(function() S.toggle('food'); S.toggle('water') end, VK_F3),
    createHotkey(function() S.toggle('energy') end,  VK_F4),
    createHotkey(function() S.toggle('noradiation'); S.toggle('temperature') end, VK_F5),
    createHotkey(function() S.speedStep(S.SPEED_STEP) end,  VK_F6),
    createHotkey(function() S.speedStep(-S.SPEED_STEP) end, VK_F7),
    createHotkey(function() S.status() end,                 VK_F8),
    createHotkey(function() S.toggleCrafting() end,         VK_F9),
    createHotkey(function() S.toggleTools() end,            VK_F10),
    createHotkey(function() S.toggleJump() end,             VK_F11),
  }
  log('Ready. F1 Health | F2 O2 | F3 Food+Water | F4 Energy | F5 Rad+Temp | F6/F7 Speed +/-1x | F8 Status | F9 Craft+Unlock | F10 Tools | F11 Infinite Jump')
end

function S.stop()
  if S.timer then S.timer.destroy(); S.timer = nil end
  if S.hotkeys then for _, h in ipairs(S.hotkeys) do h.destroy() end; S.hotkeys = nil end
  if S.cheats then for _, c in pairs(S.cheats) do c.on = false end end
  if S.defaults and S.defaults.swim then pcall(S.speed, 1) end
  if S.craftMode then S.craftMode = false; pcall(S.setCraftingCheats, false, true) end
  if S.toolsMode then S.toolsMode = false; pcall(S.setToolsCheats, false) end
  if S.jumpMode  then S.jumpMode  = false; pcall(S.setInfiniteJump, false) end
  if S.syncUI    then pcall(S.syncUI) end
  if S.parentRec then pcall(function() S.parentRec.Collapsed = true end) end
  pcall(cycleFullCompact, nil, false)
  log('Stopped.')
end

S.start(memrec)

{$asm}
[DISABLE]
{$lua}
if syntaxcheck then return end
if SN2 and SN2.stop then pcall(SN2.stop) end
{$asm}
</AssemblerScript>
      <CheatEntries>
        <CheatEntry>
          <ID>1</ID>
          <Description>"F1 - Infinite Health"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f1', true) end
{$asm}
[DISABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f1', false) end
{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>2</ID>
          <Description>"F2 - Infinite Oxygen"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f2', true) end
{$asm}
[DISABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f2', false) end
{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>3</ID>
          <Description>"F3 - Infinite Food &amp; Water"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f3', true) end
{$asm}
[DISABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f3', false) end
{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>4</ID>
          <Description>"F4 - Infinite Energy"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f4', true) end
{$asm}
[DISABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f4', false) end
{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>5</ID>
          <Description>"F5 - No Radiation &amp; Stable Temperature"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f5', true) end
{$asm}
[DISABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f5', false) end
{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>6</ID>
          <Description>"F6 - Increase Speed (+1.0x) [x1.0]"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then
  SN2.onChildUI('f6', true)
  local t = createTimer(nil, false); t.Interval = 30
  t.OnTimer = function(tm) tm.destroy(); if SN2 then SN2.syncingUI = true; memrec.Active = false; SN2.syncingUI = false end end
  t.Enabled = true
end
{$asm}
[DISABLE]
{$lua}
if syntaxcheck then return end
{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>7</ID>
          <Description>"F7 - Decrease Speed (-1.0x)"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then
  SN2.onChildUI('f7', true)
  local t = createTimer(nil, false); t.Interval = 30
  t.OnTimer = function(tm) tm.destroy(); if SN2 then SN2.syncingUI = true; memrec.Active = false; SN2.syncingUI = false end end
  t.Enabled = true
end
{$asm}
[DISABLE]
{$lua}
if syntaxcheck then return end
{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>8</ID>
          <Description>"F8 - Print Player Status (Lua Console)"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then
  SN2.onChildUI('f8', true)
  local t = createTimer(nil, false); t.Interval = 30
  t.OnTimer = function(tm) tm.destroy(); if SN2 then SN2.syncingUI = true; memrec.Active = false; SN2.syncingUI = false end end
  t.Enabled = true
end
{$asm}
[DISABLE]
{$lua}
if syntaxcheck then return end
{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>9</ID>
          <Description>"F9 - Free Craft &amp; Unlock All Recipes"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f9', true) end
{$asm}
[DISABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f9', false) end
{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>10</ID>
          <Description>"F10 - Fast Scan / Build / Repair &amp; Infinite Battery"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f10', true) end
{$asm}
[DISABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f10', false) end
{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>11</ID>
          <Description>"F11 - Infinite Air Jump (Multi-Jump)"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f11', true) end
{$asm}
[DISABLE]
{$lua}
if syntaxcheck then return end
if SN2 and not SN2.syncingUI then SN2.onChildUI('f11', false) end
{$asm}
</AssemblerScript>
        </CheatEntry>
      </CheatEntries>
    </CheatEntry>
  </CheatEntries>
  <UserdefinedSymbols/>
</CheatTable>
