<?xml version='1.0' encoding='utf-8'?>
<CheatTable CheatEngineTableVersion="45">
  <CheatEntries>
    <CheatEntry>
      <ID>1</ID>
      <Description>"Auto-Attach and Version Check"</Description>
      <GroupHeader>1</GroupHeader>
    </CheatEntry>
    <CheatEntry>
      <ID>2</ID>
      <Description>"☕ Fuel the Cheats — Tip Katzy (Toggle to open my Ko-fi page)"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
shellExecute('https://ko-fi.com/katzy')
local record=memrec
createTimer(100,function() record.Active=false end)
{$asm}
[DISABLE]
</AssemblerScript>
    </CheatEntry>
    <CheatEntry>
      <ID>3</ID>
      <Description>"How to use - Katzy"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
showMessage([[Table identification: Katzy.

Allow the table Lua and start either game. Tick its MAIN and choose options in the
main menu or during a single-player match. Menu selections activate when a mission
or skirmish is ready. Both MAIN sections are available when both games run;
switching MAIN turns the previous game's options off before attaching to the other game.

Infinite Money adds a 30,000-credit allowance. Earnings can increase the total;
purchases spend the surplus down to that allowance. Turning it off removes only
the allowance, keeping your unspent normal credits. Silos Needed is muted while enabled;
normal harvesting and storage rules still apply.
Infinite Power adds enough supply to keep 100 power spare whenever needed.
Turning it off removes the extra supply and updates low-power behavior normally.
Instant Build completes paid unit, structure and upgrade queues on their next update.
You still need the price and prerequisites; placement and exit animations remain.
Turning it off restores normal speed for future progress; completed production stays completed.
Instant Superweapons and Support Powers makes your powers ready and removes their credit costs.
Required structures, upgrades and valid targets still apply. Unit and building purchases cost normally.
Switching it off restores normal costs and the existing cooldown schedule.
Reveal Map - Visual Only reveals terrain and renders objects without granting gameplay vision.
Hidden targets can still be unavailable for orders; scripted hiding and stealth are not bypassed.
Reveal Map - Full grants real map vision and can trigger discoveries, encounters or mission events.
Switching it off removes the extra vision but cannot undo discoveries or triggered events.
The two Reveal Map options are mutually exclusive. Prefer Visual Only for missions.

Money, power and map changes take effect on a game update. If paused, resume briefly.
Clear All or unticking MAIN immediately unticks every option. If paused, cleanup
finishes when you resume; the status row shows when it is pending. Options cannot
be enabled again until cleanup finishes. Your selections stay checked across map changes and apply again once the new map runs.
While loading, the status row shows that selections are waiting. Clear All cancels them.
Closing Cheat Engine requests cleanup and then closes automatically. If the game is
paused, resume it once to finish; no second close request is needed.
Turn options off before saving, switching processes manually or replacing the table.

Fuel the Cheats opens Katzy's Ko-fi page only when deliberately selected.]])
local record=memrec
createTimer(100,function() record.Active=false end)
{$asm}
[DISABLE]
</AssemblerScript>
    </CheatEntry>
    <CheatEntry>
      <ID>4</ID>
      <Description>"Clear All"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]
{$lua}
if syntaxcheck then return end
if CNC3Katzy then CNC3Katzy.clear() end
local record=memrec
createTimer(100,function() record.Active=false end)
{$asm}
[DISABLE]
</AssemblerScript>
    </CheatEntry>
    <CheatEntry>
      <ID>10</ID>
      <Description>"[MAIN] Command &amp; Conquer 3: Tiberium Wars"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
      <Options moHideChildren="1" />
      <CheatEntries>
        <CheatEntry>
          <ID>11</ID>
          <Description>"Infinite Money"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>12</ID>
          <Description>"Infinite Power"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>13</ID>
          <Description>"Instant Build"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>14</ID>
          <Description>"Instant Superweapons and Support Powers"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>15</ID>
          <Description>"Reveal Map - Visual Only"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>16</ID>
          <Description>"Reveal Map - Full"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
        </CheatEntry>
      </CheatEntries>
    </CheatEntry>
    <CheatEntry>
      <ID>20</ID>
      <Description>"[MAIN] Command &amp; Conquer 3: Kane's Wrath"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
      <Options moHideChildren="1" />
      <CheatEntries>
        <CheatEntry>
          <ID>21</ID>
          <Description>"Infinite Money"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>22</ID>
          <Description>"Infinite Power"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>23</ID>
          <Description>"Instant Build"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>24</ID>
          <Description>"Instant Superweapons and Support Powers"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>25</ID>
          <Description>"Reveal Map - Visual Only"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>26</ID>
          <Description>"Reveal Map - Full"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]
[DISABLE]
</AssemblerScript>
        </CheatEntry>
      </CheatEntries>
    </CheatEntry>
  </CheatEntries>
  <UserdefinedSymbols />
  <LuaScript>--[[
Table identification: Katzy
Command &amp; Conquer 3 | Tiberium Wars 1.10 / Kane's Wrath 1.3 | v1.11
Player-owned cheats for the supported Steam builds.
Selections persist across maps; Clear All restores captured original code.
]]
if CNC3Katzy and CNC3Katzy.shutdown()==false then
  showMessage('Resume the previous game so its active options can finish turning off, then reload this table.')
  return
end
local S={installed={}, closing=false}
CNC3Katzy=S
local configs={
tw={module='cnc3game.dat', hash='b2f584c0aaecf38a7815d9770acc4d5a', title="Tiberium Wars", version='1.10.0.0', player=0x7EE110, logic=0x7EE574, shroud=0x7F3494, scripts={controller=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3game.dat+0x7EE110)
define(LOGICGLOBAL,cnc3game.dat+0x7EE574)
define(POWERADD,cnc3game.dat+0xA38F2)
define(SHROUDGLOBAL,cnc3game.dat+0x7F3494)
define(REVEALADD,cnc3game.dat+0x5E3674)
define(REVEALOFF,cnc3game.dat+0x5E4C31)
define(REFRESH,cnc3game.dat+0x5E36B0)
aobscanmodule(cnc_controller_hook,cnc3game.dat,56 57 6a 14 8d 71 24 5f 8b 0e e8 0a ff ff ff 83 c6 04 4f 75 f3 5f 5e c3)
assert(cnc_controller_hook,56 57 6a 14 8d 71 24)
alloc(cnc_controller_code,0x400,cnc_controller_hook)
alloc(cnc_state,0x80)
registersymbol(cnc_state)
label(cnc_controller_return)
label(ctl_money_off)
label(ctl_money_remaining)
label(ctl_power)
label(ctl_power_delta)
label(ctl_reveal)
label(ctl_reveal_update)
label(ctl_reveal_off)
label(ctl_visual_refresh)
label(ctl_invalid)
label(ctl_done)
registersymbol(cnc_controller_hook)
cnc_state:
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd (float)100.0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0

cnc_controller_code:
pushfd
pushad
cmp dword ptr [cnc_state+1C],1
jne ctl_done
mov eax,[PLAYERGLOBAL]
test eax,eax
je ctl_invalid
mov eax,[eax+1C]
cmp eax,[cnc_state]
jne ctl_invalid
mov ebx,[LOGICGLOBAL]
cmp ebx,[cnc_state+24]
jne ctl_invalid
test ebx,ebx
je ctl_invalid
mov edx,[ebx+38]
cmp edx,[cnc_state+20]
jb ctl_invalid
mov [cnc_state+20],edx
mov ebx,[eax+60]
cmp ebx,[cnc_state+4]
jne ctl_invalid
mov ecx,[eax+80]
cmp ecx,[cnc_state+8]
jne ctl_invalid
mov edx,[SHROUDGLOBAL]
cmp edx,[cnc_state+44]
jne ctl_invalid
mov edx,[cnc_state+0xC]
cmp edx,[cnc_state+10]
je ctl_power
test edx,edx
jz ctl_money_off
add dword ptr [ebx+4],7530
add dword ptr [ebx+8],7530
mov dword ptr [cnc_state+10],1
jmp ctl_power
ctl_money_off:
mov edx,[ebx+4]
sub edx,7530
jnc ctl_money_remaining
xor edx,edx
ctl_money_remaining:
mov [ebx+4],edx
sub dword ptr [ebx+8],7530
mov dword ptr [cnc_state+10],0
ctl_power:
xor edx,edx
cmp dword ptr [cnc_state+14],0
je ctl_power_delta
mov edx,[ecx+8]
add edx,64
sub edx,[ecx+4]
add edx,[cnc_state+18]
jns ctl_power_delta
xor edx,edx
ctl_power_delta:
mov eax,edx
sub edx,[cnc_state+18]
je ctl_reveal
mov [cnc_state+18],eax
mov ebp,esp
sub esp,220
and esp,-10
fxsave [esp]
push edx
call POWERADD
fxrstor [esp]
mov esp,ebp
ctl_reveal:
mov eax,[cnc_state+34]
cmp eax,[cnc_state+38]
jne ctl_reveal_update
mov eax,[cnc_state+3C]
cmp eax,[cnc_state+40]
je ctl_done
ctl_reveal_update:
mov ebp,esp
sub esp,220
and esp,-10
fxsave [esp]
mov edi,[cnc_state+44]
mov esi,[cnc_state]
mov eax,[cnc_state+34]
cmp eax,[cnc_state+38]
je ctl_visual_refresh
mov ecx,[edi+1C]
push dword ptr [esi+48]
test eax,eax
jz ctl_reveal_off
call REVEALADD
mov dword ptr [cnc_state+38],1
jmp ctl_visual_refresh
ctl_reveal_off:
call REVEALOFF
mov dword ptr [cnc_state+38],0
ctl_visual_refresh:
mov ecx,[edi+1C]
call REFRESH
mov eax,[cnc_state+3C]
mov [cnc_state+40],eax
fxrstor [esp]
mov esp,ebp
jmp ctl_done
ctl_invalid:
mov dword ptr [cnc_state+1C],0
ctl_done:
popad
popfd

push esi
push edi
push 14
lea esi,[ecx+24]
jmp cnc_controller_return
cnc_controller_hook:
jmp cnc_controller_code
nop 2
cnc_controller_return:
[DISABLE]
cnc_controller_hook:
db 56 57 6a 14 8d 71 24
unregistersymbol(cnc_controller_hook)
dealloc(cnc_controller_code)
unregistersymbol(cnc_state)
dealloc(cnc_state)
]==],money=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3game.dat+0x7EE110)
define(LOGICGLOBAL,cnc3game.dat+0x7EE574)
aobscanmodule(cnc_money_hook,cnc3game.dat,29 06 8b 53 0c 8b 0d 10 e1 be 00 01 45 50 52 e8 20 37 ff ff 8b 4d 5c 89)
assert(cnc_money_hook,29 06 8b 53 0c)
alloc(cnc_money_code,0x400,cnc_money_hook)
label(cnc_money_return)
label(money_done)
registersymbol(cnc_money_hook)

cnc_money_code:
sub [esi],eax
pushfd
push ecx
cmp dword ptr [cnc_state+1C],1
jne money_done
cmp dword ptr [cnc_state+10],1
jne money_done
cmp ebx,[cnc_state+4]
jne money_done
mov ecx,[PLAYERGLOBAL]
test ecx,ecx
je money_done
mov ecx,[ecx+1C]
cmp ecx,[cnc_state]
jne money_done
mov ecx,[LOGICGLOBAL]
cmp ecx,[cnc_state+24]
jne money_done
test ecx,ecx
je money_done
mov ecx,[ecx+38]
cmp ecx,[cnc_state+20]
jb money_done
cmp dword ptr [esi],7530
jae money_done
mov dword ptr [esi],7530
money_done:
pop ecx
popfd
mov edx,[ebx+0xC]

jmp cnc_money_return
cnc_money_hook:
jmp cnc_money_code
cnc_money_return:
[DISABLE]
cnc_money_hook:
db 29 06 8b 53 0c
unregistersymbol(cnc_money_hook)
dealloc(cnc_money_code)
]==],instant=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3game.dat+0x7EE110)
define(LOGICGLOBAL,cnc3game.dat+0x7EE574)
aobscanmodule(cnc_instant_hook,cnc3game.dat,f3 0f 10 4b 20 f3 0f 58 4b 1c f3 0f 10 05 54 4e a3 00 0f 2f c1 f3 0f 11)
assert(cnc_instant_hook,f3 0f 10 4b 20)
alloc(cnc_instant_code,0x400,cnc_instant_hook)
label(cnc_instant_return)
label(build_done)
registersymbol(cnc_instant_hook)

cnc_instant_code:
movss xmm1,[ebx+20]
pushfd
push eax
cmp dword ptr [cnc_state+1C],1
jne build_done
cmp dword ptr [cnc_state+28],1
jne build_done
cmp edi,[cnc_state]
jne build_done
mov eax,[PLAYERGLOBAL]
test eax,eax
je build_done
cmp edi,[eax+1C]
jne build_done
mov eax,[LOGICGLOBAL]
cmp eax,[cnc_state+24]
jne build_done
test eax,eax
je build_done
mov eax,[eax+38]
cmp eax,[cnc_state+20]
jb build_done
movss xmm1,[cnc_state+2C]
build_done:
pop eax
popfd

jmp cnc_instant_return
cnc_instant_hook:
jmp cnc_instant_code
cnc_instant_return:
[DISABLE]
cnc_instant_hook:
db f3 0f 10 4b 20
unregistersymbol(cnc_instant_hook)
dealloc(cnc_instant_code)
]==],ready=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3game.dat+0x7EE110)
define(LOGICGLOBAL,cnc3game.dat+0x7EE574)
define(OWNER_OFFSET,0x33C)
aobscanmodule(cnc_ready_hook,cnc3game.dat,a1 74 e5 be 00 80 b8 a2 00 00 00 00 56 8b f1 75 04 32 c0 5e c3 80 7e 28)
assert(cnc_ready_hook,a1 74 e5 be 00)
alloc(cnc_ready_code,0x400,cnc_ready_hook)
label(cnc_ready_return)
label(ready_normal)
registersymbol(cnc_ready_hook)

cnc_ready_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne ready_normal
cmp dword ptr [cnc_state+30],1
jne ready_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je ready_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne ready_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je ready_normal
cmp ebx,[cnc_state+24]
jne ready_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb ready_normal
mov ebx,[ecx-8]
test ebx,ebx
je ready_normal
mov ebx,[ebx+OWNER_OFFSET]
test ebx,ebx
je ready_normal
mov ebx,[ebx+4]
test ebx,ebx
je ready_normal
cmp edx,[ebx+8]
jne ready_normal
pop ebx
pop edx
popfd
mov eax,1
ret
ready_normal:
pop ebx
pop edx
popfd
db a1 74 e5 be 00

jmp cnc_ready_return
cnc_ready_hook:
jmp cnc_ready_code
cnc_ready_return:
[DISABLE]
cnc_ready_hook:
db a1 74 e5 be 00
unregistersymbol(cnc_ready_hook)
dealloc(cnc_ready_code)
]==],progress=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3game.dat+0x7EE110)
define(LOGICGLOBAL,cnc3game.dat+0x7EE574)
define(OWNER_OFFSET,0x33C)
aobscanmodule(cnc_progress_hook,cnc3game.dat,55 8b ec 51 a1 74 e5 be 00 80 b8 a2 00 00 00 00 53 56 57 8b f1 0f 84 ae)
assert(cnc_progress_hook,55 8b ec 51 a1 74 e5 be 00)
alloc(cnc_progress_code,0x400,cnc_progress_hook)
label(cnc_progress_return)
label(progress_normal)
registersymbol(cnc_progress_hook)

cnc_progress_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne progress_normal
cmp dword ptr [cnc_state+30],1
jne progress_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je progress_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne progress_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je progress_normal
cmp ebx,[cnc_state+24]
jne progress_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb progress_normal
mov ebx,[ecx-8]
test ebx,ebx
je progress_normal
mov ebx,[ebx+OWNER_OFFSET]
test ebx,ebx
je progress_normal
mov ebx,[ebx+4]
test ebx,ebx
je progress_normal
cmp edx,[ebx+8]
jne progress_normal
pop ebx
pop edx
popfd
fld1
ret
progress_normal:
pop ebx
pop edx
popfd
db 55 8b ec 51 a1 74 e5 be 00

jmp cnc_progress_return
cnc_progress_hook:
jmp cnc_progress_code
nop 4
cnc_progress_return:
[DISABLE]
cnc_progress_hook:
db 55 8b ec 51 a1 74 e5 be 00
unregistersymbol(cnc_progress_hook)
dealloc(cnc_progress_code)
]==],deadline=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3game.dat+0x7EE110)
define(LOGICGLOBAL,cnc3game.dat+0x7EE574)
define(OWNER_OFFSET,0x33C)
aobscanmodule(cnc_deadline_hook,cnc3game.dat,56 8b f1 8b 06 57 ff 50 1c 6a 0d 8b c8 e8 35 15 ec ff 84 c0 74 23 8b 4e)
assert(cnc_deadline_hook,56 8b f1 8b 06)
alloc(cnc_deadline_code,0x400,cnc_deadline_hook)
label(cnc_deadline_return)
label(deadline_normal)
registersymbol(cnc_deadline_hook)

cnc_deadline_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne deadline_normal
cmp dword ptr [cnc_state+30],1
jne deadline_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je deadline_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne deadline_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je deadline_normal
cmp ebx,[cnc_state+24]
jne deadline_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb deadline_normal
mov ebx,[ecx-8]
test ebx,ebx
je deadline_normal
mov ebx,[ebx+OWNER_OFFSET]
test ebx,ebx
je deadline_normal
mov ebx,[ebx+4]
test ebx,ebx
je deadline_normal
cmp edx,[ebx+8]
jne deadline_normal
pop ebx
pop edx
popfd
mov eax,[LOGICGLOBAL]
mov eax,[eax+38]
ret
deadline_normal:
pop ebx
pop edx
popfd
db 56 8b f1 8b 06

jmp cnc_deadline_return
cnc_deadline_hook:
jmp cnc_deadline_code
cnc_deadline_return:
[DISABLE]
cnc_deadline_hook:
db 56 8b f1 8b 06
unregistersymbol(cnc_deadline_hook)
dealloc(cnc_deadline_code)
]==],afford=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3game.dat+0x7EE110)
define(LOGICGLOBAL,cnc3game.dat+0x7EE574)
define(OWNER_OFFSET,0x33C)
aobscanmodule(cnc_afford_hook,cnc3game.dat,56 8b 74 24 08 8b 46 18 83 b8 30 01 00 00 00 7c 04 b0 01 eb 2a 80 3d 3a)
assert(cnc_afford_hook,56 8b 74 24 08)
alloc(cnc_afford_code,0x400,cnc_afford_hook)
label(cnc_afford_return)
label(afford_normal)
registersymbol(cnc_afford_hook)

cnc_afford_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne afford_normal
cmp dword ptr [cnc_state+30],1
jne afford_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je afford_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne afford_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je afford_normal
cmp ebx,[cnc_state+24]
jne afford_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb afford_normal
mov ebx,[ecx+0xC]
test ebx,ebx
je afford_normal
mov ebx,[ebx+OWNER_OFFSET]
test ebx,ebx
je afford_normal
mov ebx,[ebx+4]
test ebx,ebx
je afford_normal
cmp edx,[ebx+8]
jne afford_normal
pop ebx
pop edx
popfd
mov eax,1
ret 4
afford_normal:
pop ebx
pop edx
popfd
db 56 8b 74 24 08

jmp cnc_afford_return
cnc_afford_hook:
jmp cnc_afford_code
cnc_afford_return:
[DISABLE]
cnc_afford_hook:
db 56 8b 74 24 08
unregistersymbol(cnc_afford_hook)
dealloc(cnc_afford_code)
]==],spcost=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3game.dat+0x7EE110)
define(LOGICGLOBAL,cnc3game.dat+0x7EE574)
aobscanmodule(cnc_spcost_hook,cnc3game.dat,8b 80 30 01 00 00 85 c0 8b 75 fc 74 47 8b 57 0c 8b 4e 60 8b 92 e8 00 00)
assert(cnc_spcost_hook,8b 80 30 01 00 00)
alloc(cnc_spcost_code,0x400,cnc_spcost_hook)
label(cnc_spcost_return)
label(spcost_normal)
registersymbol(cnc_spcost_hook)

cnc_spcost_code:
mov eax,[eax+130]
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne spcost_normal
cmp dword ptr [cnc_state+30],1
jne spcost_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je spcost_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne spcost_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je spcost_normal
cmp ebx,[cnc_state+24]
jne spcost_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb spcost_normal
cmp edx,[ebp-4]
jne spcost_normal
test eax,eax
jns spcost_normal
xor eax,eax
spcost_normal:
pop ebx
pop edx
popfd

jmp cnc_spcost_return
cnc_spcost_hook:
jmp cnc_spcost_code
nop 1
cnc_spcost_return:
[DISABLE]
cnc_spcost_hook:
db 8b 80 30 01 00 00
unregistersymbol(cnc_spcost_hook)
dealloc(cnc_spcost_code)
]==],notify=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3game.dat+0x7EE110)
define(LOGICGLOBAL,cnc3game.dat+0x7EE574)
aobscanmodule(cnc_notify_hook,cnc3game.dat,55 8b ec 83 ec 18 ff 75 10 33 c9 ff 75 0c b8 96 e2 5a 00 ff 75 08 51 50 8d 45 e8 50 e8 9a f9 ff ff 83 c4 18 50 e8 9f ff)
assert(cnc_notify_hook,55 8b ec 83 ec 18)
alloc(cnc_notify_code,0x400,cnc_notify_hook)
label(cnc_notify_return)
label(notify_normal)
registersymbol(cnc_notify_hook)

cnc_notify_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne notify_normal
cmp dword ptr [cnc_state+3C],1
jne notify_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je notify_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne notify_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je notify_normal
cmp ebx,[cnc_state+24]
jne notify_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb notify_normal
mov dword ptr [esp+18],1
notify_normal:
pop ebx
pop edx
popfd
db 55 8b ec 83 ec 18

jmp cnc_notify_return
cnc_notify_hook:
jmp cnc_notify_code
nop 1
cnc_notify_return:
[DISABLE]
cnc_notify_hook:
db 55 8b ec 83 ec 18
unregistersymbol(cnc_notify_hook)
dealloc(cnc_notify_code)
]==],drawcull=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3game.dat+0x7EE110)
define(LOGICGLOBAL,cnc3game.dat+0x7EE574)
aobscanmodule(cnc_drawcull_hook,cnc3game.dat,83 f8 03 89 45 ec 7c 5e 83 be 28 02 00 00 00 74 55 d9 05 40 4f a3 00 6a)
assert(cnc_drawcull_hook,83 f8 03 89 45 ec)
alloc(cnc_drawcull_code,0x400,cnc_drawcull_hook)
label(cnc_drawcull_return)
label(drawcull_normal)
registersymbol(cnc_drawcull_hook)

cnc_drawcull_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne drawcull_normal
cmp dword ptr [cnc_state+3C],1
jne drawcull_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je drawcull_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne drawcull_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je drawcull_normal
cmp ebx,[cnc_state+24]
jne drawcull_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb drawcull_normal
mov ebx,[ebp-0xC]
cmp ebx,[edx+48]
jne drawcull_normal
mov eax,1
drawcull_normal:
pop ebx
pop edx
popfd
db 83 f8 03 89 45 ec

jmp cnc_drawcull_return
cnc_drawcull_hook:
jmp cnc_drawcull_code
nop 1
cnc_drawcull_return:
[DISABLE]
cnc_drawcull_hook:
db 83 f8 03 89 45 ec
unregistersymbol(cnc_drawcull_hook)
dealloc(cnc_drawcull_code)
]==],drawshade=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3game.dat+0x7EE110)
define(LOGICGLOBAL,cnc3game.dat+0x7EE574)
aobscanmodule(cnc_drawshade_hook,cnc3game.dat,83 f8 01 89 45 fc 75 10 a1 74 e5 be 00 8b 40 38 89 87 28 02 00 00 eb 66)
assert(cnc_drawshade_hook,83 f8 01 89 45 fc)
alloc(cnc_drawshade_code,0x400,cnc_drawshade_hook)
label(cnc_drawshade_return)
label(drawshade_normal)
registersymbol(cnc_drawshade_hook)

cnc_drawshade_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne drawshade_normal
cmp dword ptr [cnc_state+3C],1
jne drawshade_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je drawshade_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne drawshade_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je drawshade_normal
cmp ebx,[cnc_state+24]
jne drawshade_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb drawshade_normal
mov ebx,[ebp+10]
cmp ebx,[edx+48]
jne drawshade_normal
mov eax,1
drawshade_normal:
pop ebx
pop edx
popfd
db 83 f8 01 89 45 fc

jmp cnc_drawshade_return
cnc_drawshade_hook:
jmp cnc_drawshade_code
nop 1
cnc_drawshade_return:
[DISABLE]
cnc_drawshade_hook:
db 83 f8 01 89 45 fc
unregistersymbol(cnc_drawshade_hook)
dealloc(cnc_drawshade_code)
]==],silos=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3game.dat+0x7EE110)
define(LOGICGLOBAL,cnc3game.dat+0x7EE574)
aobscanmodule(cnc_silos_hook,cnc3game.dat,50 50 50 6a 1c e8 d8 8f e7 ff e9 80 00 00 00 8b 45 08 8b 80 e8 00 00 00)
assert(cnc_silos_hook,50 50 50 6a 1c)
alloc(cnc_silos_code,0x400,cnc_silos_hook)
label(cnc_silos_return)
label(silos_normal)
registersymbol(cnc_silos_hook)

cnc_silos_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne silos_normal
cmp dword ptr [cnc_state+C],1
jne silos_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je silos_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne silos_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je silos_normal
cmp ebx,[cnc_state+24]
jne silos_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb silos_normal
cmp edx,[esp]
jne silos_normal
pop ebx
pop edx
popfd
jmp cnc_silos_hook+0A
silos_normal:
pop ebx
pop edx
popfd
db 50 50 50 6a 1c

jmp cnc_silos_return
cnc_silos_hook:
jmp cnc_silos_code
cnc_silos_return:
[DISABLE]
cnc_silos_hook:
db 50 50 50 6a 1c
unregistersymbol(cnc_silos_hook)
dealloc(cnc_silos_code)
]==]}},
kw={module='cnc3ep1.dat', hash='99072ea8b1c3aa09ff72d1f625f86985', title="Kane's Wrath", version='1.3.0.0', player=0x7F7B10, logic=0x7F7F98, shroud=0x7FBF18, scripts={controller=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3ep1.dat+0x7F7B10)
define(LOGICGLOBAL,cnc3ep1.dat+0x7F7F98)
define(POWERADD,cnc3ep1.dat+0xEA20B)
define(SHROUDGLOBAL,cnc3ep1.dat+0x7FBF18)
define(REVEALADD,cnc3ep1.dat+0x56A5A9)
define(REVEALOFF,cnc3ep1.dat+0x56BB5C)
define(REFRESH,cnc3ep1.dat+0x56A5E5)
aobscanmodule(cnc_controller_hook,cnc3ep1.dat,56 57 6a 1a 8d 71 24 5f 8b 0e e8 0a ff ff ff 83 c6 04 4f 75 f3 5f 5e c3)
assert(cnc_controller_hook,56 57 6a 1a 8d 71 24)
alloc(cnc_controller_code,0x400,cnc_controller_hook)
alloc(cnc_state,0x80)
registersymbol(cnc_state)
label(cnc_controller_return)
label(ctl_money_off)
label(ctl_money_remaining)
label(ctl_power)
label(ctl_power_delta)
label(ctl_reveal)
label(ctl_reveal_update)
label(ctl_reveal_off)
label(ctl_visual_refresh)
label(ctl_invalid)
label(ctl_done)
registersymbol(cnc_controller_hook)
cnc_state:
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd (float)100.0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0

cnc_controller_code:
pushfd
pushad
cmp dword ptr [cnc_state+1C],1
jne ctl_done
mov eax,[PLAYERGLOBAL]
test eax,eax
je ctl_invalid
mov eax,[eax+1C]
cmp eax,[cnc_state]
jne ctl_invalid
mov ebx,[LOGICGLOBAL]
cmp ebx,[cnc_state+24]
jne ctl_invalid
test ebx,ebx
je ctl_invalid
mov edx,[ebx+38]
cmp edx,[cnc_state+20]
jb ctl_invalid
mov [cnc_state+20],edx
mov ebx,[eax+60]
cmp ebx,[cnc_state+4]
jne ctl_invalid
mov ecx,[eax+80]
cmp ecx,[cnc_state+8]
jne ctl_invalid
mov edx,[SHROUDGLOBAL]
cmp edx,[cnc_state+44]
jne ctl_invalid
mov edx,[cnc_state+0xC]
cmp edx,[cnc_state+10]
je ctl_power
test edx,edx
jz ctl_money_off
add dword ptr [ebx+4],7530
add dword ptr [ebx+8],7530
mov dword ptr [cnc_state+10],1
jmp ctl_power
ctl_money_off:
mov edx,[ebx+4]
sub edx,7530
jnc ctl_money_remaining
xor edx,edx
ctl_money_remaining:
mov [ebx+4],edx
sub dword ptr [ebx+8],7530
mov dword ptr [cnc_state+10],0
ctl_power:
xor edx,edx
cmp dword ptr [cnc_state+14],0
je ctl_power_delta
mov edx,[ecx+8]
add edx,64
sub edx,[ecx+4]
add edx,[cnc_state+18]
jns ctl_power_delta
xor edx,edx
ctl_power_delta:
mov eax,edx
sub edx,[cnc_state+18]
je ctl_reveal
mov [cnc_state+18],eax
mov ebp,esp
sub esp,220
and esp,-10
fxsave [esp]
push edx
call POWERADD
fxrstor [esp]
mov esp,ebp
ctl_reveal:
mov eax,[cnc_state+34]
cmp eax,[cnc_state+38]
jne ctl_reveal_update
mov eax,[cnc_state+3C]
cmp eax,[cnc_state+40]
je ctl_done
ctl_reveal_update:
mov ebp,esp
sub esp,220
and esp,-10
fxsave [esp]
mov edi,[cnc_state+44]
mov esi,[cnc_state]
mov eax,[cnc_state+34]
cmp eax,[cnc_state+38]
je ctl_visual_refresh
mov ecx,[edi+1C]
push dword ptr [esi+48]
test eax,eax
jz ctl_reveal_off
call REVEALADD
mov dword ptr [cnc_state+38],1
jmp ctl_visual_refresh
ctl_reveal_off:
call REVEALOFF
mov dword ptr [cnc_state+38],0
ctl_visual_refresh:
mov ecx,[edi+1C]
call REFRESH
mov eax,[cnc_state+3C]
mov [cnc_state+40],eax
fxrstor [esp]
mov esp,ebp
jmp ctl_done
ctl_invalid:
mov dword ptr [cnc_state+1C],0
ctl_done:
popad
popfd

push esi
push edi
push 1A
lea esi,[ecx+24]
jmp cnc_controller_return
cnc_controller_hook:
jmp cnc_controller_code
nop 2
cnc_controller_return:
[DISABLE]
cnc_controller_hook:
db 56 57 6a 1a 8d 71 24
unregistersymbol(cnc_controller_hook)
dealloc(cnc_controller_code)
unregistersymbol(cnc_state)
dealloc(cnc_state)
]==],money=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3ep1.dat+0x7F7B10)
define(LOGICGLOBAL,cnc3ep1.dat+0x7F7F98)
aobscanmodule(cnc_money_hook,cnc3ep1.dat,29 06 8b 53 0c 8b 0d 10 7b bf 00 01 45 50 52 e8 54 32 ff ff 8b 4d 5c 89)
assert(cnc_money_hook,29 06 8b 53 0c)
alloc(cnc_money_code,0x400,cnc_money_hook)
label(cnc_money_return)
label(money_done)
registersymbol(cnc_money_hook)

cnc_money_code:
sub [esi],eax
pushfd
push ecx
cmp dword ptr [cnc_state+1C],1
jne money_done
cmp dword ptr [cnc_state+10],1
jne money_done
cmp ebx,[cnc_state+4]
jne money_done
mov ecx,[PLAYERGLOBAL]
test ecx,ecx
je money_done
mov ecx,[ecx+1C]
cmp ecx,[cnc_state]
jne money_done
mov ecx,[LOGICGLOBAL]
cmp ecx,[cnc_state+24]
jne money_done
test ecx,ecx
je money_done
mov ecx,[ecx+38]
cmp ecx,[cnc_state+20]
jb money_done
cmp dword ptr [esi],7530
jae money_done
mov dword ptr [esi],7530
money_done:
pop ecx
popfd
mov edx,[ebx+0xC]

jmp cnc_money_return
cnc_money_hook:
jmp cnc_money_code
cnc_money_return:
[DISABLE]
cnc_money_hook:
db 29 06 8b 53 0c
unregistersymbol(cnc_money_hook)
dealloc(cnc_money_code)
]==],instant=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3ep1.dat+0x7F7B10)
define(LOGICGLOBAL,cnc3ep1.dat+0x7F7F98)
aobscanmodule(cnc_instant_hook,cnc3ep1.dat,f3 0f 10 4b 20 f3 0f 58 4b 1c f3 0f 10 05 a4 73 a1 00 0f 2f c1 f3 0f 11)
assert(cnc_instant_hook,f3 0f 10 4b 20)
alloc(cnc_instant_code,0x400,cnc_instant_hook)
label(cnc_instant_return)
label(build_done)
registersymbol(cnc_instant_hook)

cnc_instant_code:
movss xmm1,[ebx+20]
pushfd
push eax
cmp dword ptr [cnc_state+1C],1
jne build_done
cmp dword ptr [cnc_state+28],1
jne build_done
cmp edi,[cnc_state]
jne build_done
mov eax,[PLAYERGLOBAL]
test eax,eax
je build_done
cmp edi,[eax+1C]
jne build_done
mov eax,[LOGICGLOBAL]
cmp eax,[cnc_state+24]
jne build_done
test eax,eax
je build_done
mov eax,[eax+38]
cmp eax,[cnc_state+20]
jb build_done
movss xmm1,[cnc_state+2C]
build_done:
pop eax
popfd

jmp cnc_instant_return
cnc_instant_hook:
jmp cnc_instant_code
cnc_instant_return:
[DISABLE]
cnc_instant_hook:
db f3 0f 10 4b 20
unregistersymbol(cnc_instant_hook)
dealloc(cnc_instant_code)
]==],ready=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3ep1.dat+0x7F7B10)
define(LOGICGLOBAL,cnc3ep1.dat+0x7F7F98)
define(OWNER_OFFSET,0x348)
aobscanmodule(cnc_ready_hook,cnc3ep1.dat,a1 98 7f bf 00 80 b8 a2 00 00 00 00 56 8b f1 75 04 32 c0 5e c3 80 7e 28)
assert(cnc_ready_hook,a1 98 7f bf 00)
alloc(cnc_ready_code,0x400,cnc_ready_hook)
label(cnc_ready_return)
label(ready_normal)
registersymbol(cnc_ready_hook)

cnc_ready_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne ready_normal
cmp dword ptr [cnc_state+30],1
jne ready_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je ready_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne ready_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je ready_normal
cmp ebx,[cnc_state+24]
jne ready_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb ready_normal
mov ebx,[ecx-8]
test ebx,ebx
je ready_normal
mov ebx,[ebx+OWNER_OFFSET]
test ebx,ebx
je ready_normal
mov ebx,[ebx+4]
test ebx,ebx
je ready_normal
cmp edx,[ebx+8]
jne ready_normal
pop ebx
pop edx
popfd
mov eax,1
ret
ready_normal:
pop ebx
pop edx
popfd
db a1 98 7f bf 00

jmp cnc_ready_return
cnc_ready_hook:
jmp cnc_ready_code
cnc_ready_return:
[DISABLE]
cnc_ready_hook:
db a1 98 7f bf 00
unregistersymbol(cnc_ready_hook)
dealloc(cnc_ready_code)
]==],progress=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3ep1.dat+0x7F7B10)
define(LOGICGLOBAL,cnc3ep1.dat+0x7F7F98)
define(OWNER_OFFSET,0x348)
aobscanmodule(cnc_progress_hook,cnc3ep1.dat,55 8b ec 51 a1 98 7f bf 00 80 b8 a2 00 00 00 00 53 56 57 8b f1 0f 84 ba)
assert(cnc_progress_hook,55 8b ec 51 a1 98 7f bf 00)
alloc(cnc_progress_code,0x400,cnc_progress_hook)
label(cnc_progress_return)
label(progress_normal)
registersymbol(cnc_progress_hook)

cnc_progress_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne progress_normal
cmp dword ptr [cnc_state+30],1
jne progress_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je progress_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne progress_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je progress_normal
cmp ebx,[cnc_state+24]
jne progress_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb progress_normal
mov ebx,[ecx-8]
test ebx,ebx
je progress_normal
mov ebx,[ebx+OWNER_OFFSET]
test ebx,ebx
je progress_normal
mov ebx,[ebx+4]
test ebx,ebx
je progress_normal
cmp edx,[ebx+8]
jne progress_normal
pop ebx
pop edx
popfd
fld1
ret
progress_normal:
pop ebx
pop edx
popfd
db 55 8b ec 51 a1 98 7f bf 00

jmp cnc_progress_return
cnc_progress_hook:
jmp cnc_progress_code
nop 4
cnc_progress_return:
[DISABLE]
cnc_progress_hook:
db 55 8b ec 51 a1 98 7f bf 00
unregistersymbol(cnc_progress_hook)
dealloc(cnc_progress_code)
]==],deadline=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3ep1.dat+0x7F7B10)
define(LOGICGLOBAL,cnc3ep1.dat+0x7F7F98)
define(OWNER_OFFSET,0x348)
aobscanmodule(cnc_deadline_hook,cnc3ep1.dat,56 8b f1 8b 06 57 ff 50 1c 6a 0d 8b c8 e8 5f ee e9 ff 84 c0 74 23 8b 4e)
assert(cnc_deadline_hook,56 8b f1 8b 06)
alloc(cnc_deadline_code,0x400,cnc_deadline_hook)
label(cnc_deadline_return)
label(deadline_normal)
registersymbol(cnc_deadline_hook)

cnc_deadline_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne deadline_normal
cmp dword ptr [cnc_state+30],1
jne deadline_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je deadline_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne deadline_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je deadline_normal
cmp ebx,[cnc_state+24]
jne deadline_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb deadline_normal
mov ebx,[ecx-8]
test ebx,ebx
je deadline_normal
mov ebx,[ebx+OWNER_OFFSET]
test ebx,ebx
je deadline_normal
mov ebx,[ebx+4]
test ebx,ebx
je deadline_normal
cmp edx,[ebx+8]
jne deadline_normal
pop ebx
pop edx
popfd
mov eax,[LOGICGLOBAL]
mov eax,[eax+38]
ret
deadline_normal:
pop ebx
pop edx
popfd
db 56 8b f1 8b 06

jmp cnc_deadline_return
cnc_deadline_hook:
jmp cnc_deadline_code
cnc_deadline_return:
[DISABLE]
cnc_deadline_hook:
db 56 8b f1 8b 06
unregistersymbol(cnc_deadline_hook)
dealloc(cnc_deadline_code)
]==],afford=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3ep1.dat+0x7F7B10)
define(LOGICGLOBAL,cnc3ep1.dat+0x7F7F98)
define(OWNER_OFFSET,0x348)
aobscanmodule(cnc_afford_hook,cnc3ep1.dat,56 8b 74 24 08 8b 46 1c 83 b8 40 01 00 00 00 7c 04 b0 01 eb 2a 80 3d 3a)
assert(cnc_afford_hook,56 8b 74 24 08)
alloc(cnc_afford_code,0x400,cnc_afford_hook)
label(cnc_afford_return)
label(afford_normal)
registersymbol(cnc_afford_hook)

cnc_afford_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne afford_normal
cmp dword ptr [cnc_state+30],1
jne afford_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je afford_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne afford_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je afford_normal
cmp ebx,[cnc_state+24]
jne afford_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb afford_normal
mov ebx,[ecx+0xC]
test ebx,ebx
je afford_normal
mov ebx,[ebx+OWNER_OFFSET]
test ebx,ebx
je afford_normal
mov ebx,[ebx+4]
test ebx,ebx
je afford_normal
cmp edx,[ebx+8]
jne afford_normal
pop ebx
pop edx
popfd
mov eax,1
ret 4
afford_normal:
pop ebx
pop edx
popfd
db 56 8b 74 24 08

jmp cnc_afford_return
cnc_afford_hook:
jmp cnc_afford_code
cnc_afford_return:
[DISABLE]
cnc_afford_hook:
db 56 8b 74 24 08
unregistersymbol(cnc_afford_hook)
dealloc(cnc_afford_code)
]==],spcost=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3ep1.dat+0x7F7B10)
define(LOGICGLOBAL,cnc3ep1.dat+0x7F7F98)
aobscanmodule(cnc_spcost_hook,cnc3ep1.dat,8b 80 40 01 00 00 85 c0 8b 75 fc 74 47 8b 57 0c 8b 4e 60 8b 92 ec 00 00)
assert(cnc_spcost_hook,8b 80 40 01 00 00)
alloc(cnc_spcost_code,0x400,cnc_spcost_hook)
label(cnc_spcost_return)
label(spcost_normal)
registersymbol(cnc_spcost_hook)

cnc_spcost_code:
mov eax,[eax+140]
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne spcost_normal
cmp dword ptr [cnc_state+30],1
jne spcost_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je spcost_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne spcost_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je spcost_normal
cmp ebx,[cnc_state+24]
jne spcost_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb spcost_normal
cmp edx,[ebp-4]
jne spcost_normal
test eax,eax
jns spcost_normal
xor eax,eax
spcost_normal:
pop ebx
pop edx
popfd

jmp cnc_spcost_return
cnc_spcost_hook:
jmp cnc_spcost_code
nop 1
cnc_spcost_return:
[DISABLE]
cnc_spcost_hook:
db 8b 80 40 01 00 00
unregistersymbol(cnc_spcost_hook)
dealloc(cnc_spcost_code)
]==],notify=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3ep1.dat+0x7F7B10)
define(LOGICGLOBAL,cnc3ep1.dat+0x7F7F98)
aobscanmodule(cnc_notify_hook,cnc3ep1.dat,55 8b ec 83 ec 18 ff 75 10 33 c9 ff 75 0c b8 28 f0 78 00 ff 75 08 51 50 8d 45 e8 50 e8 9a f9 ff ff 83 c4 18 50 e8 9f ff)
assert(cnc_notify_hook,55 8b ec 83 ec 18)
alloc(cnc_notify_code,0x400,cnc_notify_hook)
label(cnc_notify_return)
label(notify_normal)
registersymbol(cnc_notify_hook)

cnc_notify_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne notify_normal
cmp dword ptr [cnc_state+3C],1
jne notify_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je notify_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne notify_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je notify_normal
cmp ebx,[cnc_state+24]
jne notify_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb notify_normal
mov dword ptr [esp+18],1
notify_normal:
pop ebx
pop edx
popfd
db 55 8b ec 83 ec 18

jmp cnc_notify_return
cnc_notify_hook:
jmp cnc_notify_code
nop 1
cnc_notify_return:
[DISABLE]
cnc_notify_hook:
db 55 8b ec 83 ec 18
unregistersymbol(cnc_notify_hook)
dealloc(cnc_notify_code)
]==],drawcull=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3ep1.dat+0x7F7B10)
define(LOGICGLOBAL,cnc3ep1.dat+0x7F7F98)
aobscanmodule(cnc_drawcull_hook,cnc3ep1.dat,83 f8 03 89 45 ec 7c 5e 83 be 28 02 00 00 00 74 55 d9 05 08 6c a1 00 6a)
assert(cnc_drawcull_hook,83 f8 03 89 45 ec)
alloc(cnc_drawcull_code,0x400,cnc_drawcull_hook)
label(cnc_drawcull_return)
label(drawcull_normal)
registersymbol(cnc_drawcull_hook)

cnc_drawcull_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne drawcull_normal
cmp dword ptr [cnc_state+3C],1
jne drawcull_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je drawcull_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne drawcull_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je drawcull_normal
cmp ebx,[cnc_state+24]
jne drawcull_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb drawcull_normal
mov ebx,[ebp-0xC]
cmp ebx,[edx+48]
jne drawcull_normal
mov eax,1
drawcull_normal:
pop ebx
pop edx
popfd
db 83 f8 03 89 45 ec

jmp cnc_drawcull_return
cnc_drawcull_hook:
jmp cnc_drawcull_code
nop 1
cnc_drawcull_return:
[DISABLE]
cnc_drawcull_hook:
db 83 f8 03 89 45 ec
unregistersymbol(cnc_drawcull_hook)
dealloc(cnc_drawcull_code)
]==],drawshade=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3ep1.dat+0x7F7B10)
define(LOGICGLOBAL,cnc3ep1.dat+0x7F7F98)
aobscanmodule(cnc_drawshade_hook,cnc3ep1.dat,83 f8 01 89 45 fc 75 10 a1 98 7f bf 00 8b 40 38 89 87 28 02 00 00 eb 66)
assert(cnc_drawshade_hook,83 f8 01 89 45 fc)
alloc(cnc_drawshade_code,0x400,cnc_drawshade_hook)
label(cnc_drawshade_return)
label(drawshade_normal)
registersymbol(cnc_drawshade_hook)

cnc_drawshade_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne drawshade_normal
cmp dword ptr [cnc_state+3C],1
jne drawshade_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je drawshade_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne drawshade_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je drawshade_normal
cmp ebx,[cnc_state+24]
jne drawshade_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb drawshade_normal
mov ebx,[ebp+10]
cmp ebx,[edx+48]
jne drawshade_normal
mov eax,1
drawshade_normal:
pop ebx
pop edx
popfd
db 83 f8 01 89 45 fc

jmp cnc_drawshade_return
cnc_drawshade_hook:
jmp cnc_drawshade_code
nop 1
cnc_drawshade_return:
[DISABLE]
cnc_drawshade_hook:
db 83 f8 01 89 45 fc
unregistersymbol(cnc_drawshade_hook)
dealloc(cnc_drawshade_code)
]==],silos=[==[[ENABLE]
define(PLAYERGLOBAL,cnc3ep1.dat+0x7F7B10)
define(LOGICGLOBAL,cnc3ep1.dat+0x7F7F98)
aobscanmodule(cnc_silos_hook,cnc3ep1.dat,50 50 50 6a 1c e8 93 83 e5 ff e9 80 00 00 00 8b 45 08 8b 80 ec 00 00 00)
assert(cnc_silos_hook,50 50 50 6a 1c)
alloc(cnc_silos_code,0x400,cnc_silos_hook)
label(cnc_silos_return)
label(silos_normal)
registersymbol(cnc_silos_hook)

cnc_silos_code:
pushfd
push edx
push ebx
cmp dword ptr [cnc_state+1C],1
jne silos_normal
cmp dword ptr [cnc_state+C],1
jne silos_normal
mov edx,[PLAYERGLOBAL]
test edx,edx
je silos_normal
mov edx,[edx+1C]
cmp edx,[cnc_state]
jne silos_normal
mov ebx,[LOGICGLOBAL]
test ebx,ebx
je silos_normal
cmp ebx,[cnc_state+24]
jne silos_normal
mov ebx,[ebx+38]
cmp ebx,[cnc_state+20]
jb silos_normal
cmp edx,[esp]
jne silos_normal
pop ebx
pop edx
popfd
jmp cnc_silos_hook+0A
silos_normal:
pop ebx
pop edx
popfd
db 50 50 50 6a 1c

jmp cnc_silos_return
cnc_silos_hook:
jmp cnc_silos_code
cnc_silos_return:
[DISABLE]
cnc_silos_hook:
db 50 50 50 6a 1c
unregistersymbol(cnc_silos_hook)
dealloc(cnc_silos_code)
]==]}}
}
local list=getAddressList()
local status=list.getMemoryRecordByID(1)
local mains={tw=list.getMemoryRecordByID(10),kw=list.getMemoryRecordByID(20)}
local hookOrder={'controller','money','instant','ready','progress','deadline','afford','spcost','notify','drawcull','drawshade','silos'}
local hookSizes={controller=7,money=5,instant=5,ready=5,progress=9,deadline=5,afford=5,spcost=6,notify=6,drawcull=6,drawshade=6,silos=5}
local ids={money=1,power=2,instant=3,super=4,visual=5,full=6}
local flagOffsets={money=0xC,power=0x14,instant=0x28,super=0x30,visual=0x3C,full=0x34}
local suppress=false
local function report(message)
  if not S.recordsRemoved and S.lastStatus~=message then
    status.Description='Auto-Attach and Version Check — '..message
    S.lastStatus=message
  end
end
local function tell(message) showMessage(message) end
local function baseName(path) return (path:match('[^/\\]+$') or path):lower() end
local function run(script,disableInfo)
  local ok,a,b=pcall(autoAssemble,script,false,disableInfo)
  if not ok or not a then S.lastError=tostring(b or a); return false end
  return true,b
end
local function context()
  if not S.base or getOpenedProcessID()~=S.pid then return end
  local c=configs[S.game]
  local players=readInteger(S.base+c.player)
  local logic=readInteger(S.base+c.logic)
  local shroud=readInteger(S.base+c.shroud)
  if not shroud or shroud==0 then return end
  local shroudImpl=readInteger(shroud+0x1C)
  if not shroudImpl or shroudImpl==0 then return end
  if not players or players==0 or not logic or logic==0 then return end
  local p=readInteger(players+0x1C)
  if not p or p==0 then return end
  local money=readInteger(p+0x60)
  local energy=readInteger(p+0x80)
  local id=readInteger(p+0x48)
  if not money or money==0 or not energy or energy==0 or not id then return end
  if readInteger(money+0xC)~=id or readInteger(energy+0x14)~=p then return end
  local frame=readInteger(logic+0x38)
  local cash=readInteger(money+4)
  local cap=readInteger(money+8)
  if not frame or frame==0 or not cash or not cap or cash&gt;1000000000 or cap&gt;1000000000 then return end
  return {p=p,money=money,energy=energy,logic=logic,frame=frame,shroud=shroud}
end
local function owned()
  local c=context()
  return c and S.bound and c.p==S.bound.p and c.money==S.bound.money and
    c.energy==S.bound.energy and c.logic==S.bound.logic and c.shroud==S.bound.shroud and c.frame&gt;=(readInteger(S.state+0x20) or S.bound.frame)
end
local function write(offset,value)
  if not S.state or getOpenedProcessID()~=S.pid then return false end
  if readInteger(S.state+offset)==value then return true end
  return writeInteger(S.state+offset,value) and readInteger(S.state+offset)==value
end
local function uncheck()
  if S.recordsRemoved then return end
  suppress=true
  for _,rec in pairs(mains) do
    for i=0,rec.Count-1 do if rec.Child[i].Active then rec.Child[i].Active=false end end
    if rec.Active then rec.Active=false end
  end
  suppress=false
end
local function forgetExitedProcess()
  if not S.state or getProcesslist()[S.pid] then return false end
  -- The dead process owns no memory to restore or free. Remove only CE symbols.
  for _,kind in ipairs(hookOrder) do unregisterSymbol('cnc_'..kind..'_hook') end
  unregisterSymbol('cnc_state')
  S.installed={}; S.state=nil; S.bound=nil; S.stopping=false; S.offRequested=false
  S.pid=nil; S.base=nil; S.supported=nil
  S.transition=nil; S.candidate=nil
  uncheck()
  return true
end
local function uninstall()
  if S.state and not write(0x1C,0) then return false end
  for i=#hookOrder,1,-1 do
    local kind=hookOrder[i]
    if S.installed[kind] then
      local info=S.installed[kind]
      if info.patch then
        for i,byte in ipairs(info.patch) do
          if readBytes(info.hook+i-1,1)~=byte then
            report('Another patch changed the game code; cleanup stopped to avoid overwriting it')
            return false
          end
        end
      end
      if info.patch and info.original then
        -- Restore using captured numeric addresses; no dependency on CE's symbol
        -- or disableInfo bookkeeping surviving a table replacement.
        local ok=pcall(writeBytes,info.hook,info.original)
        for n,byte in ipairs(info.original) do
          if readBytes(info.hook+n-1,1)~=byte then ok=false; break end
        end
        if not ok then report('Code cleanup failed; keep this table open and retry Clear All'); return false end
        unregisterSymbol('cnc_'..kind..'_hook')
        if kind=='controller' then unregisterSymbol('cnc_state') end
        -- Keep detached code allocated until process exit, so an in-flight game
        -- thread can safely finish returning through it. No hooks remain active.
      elseif not run(configs[S.game].scripts[kind],info) then
        report('Cleanup failed; keep this table open and retry Clear All')
        return false
      end
      S.installed[kind]=nil
    end
  end
  S.state=nil; S.bound=nil; S.stopping=false; S.offRequested=false
  S.transition=nil; S.candidate=nil
  uncheck()
  return true
end
function S.clear()
  S.menu=nil
  if forgetExitedProcess() then return true end
  if not S.state then
    if next(S.installed) then return uninstall() end
    uncheck(); return true
  end
  if getOpenedProcessID()~=S.pid then
    report('Select the original game process to finish cleanup')
    return false
  end
  S.stopping=true
  S.offRequested=false
  if not owned() or readInteger(S.state+0x1C)==0 then
    -- The previous match no longer owns these addresses. Never restore into it.
    return uninstall()
  end
  for _,off in pairs(flagOffsets) do if not write(off,0) then return false end end
  S.offRequested=true
  uncheck()
  if readInteger(S.state+0x10)==0 and readInteger(S.state+0x18)==0 and readInteger(S.state+0x38)==0 and readInteger(S.state+0x40)==0 then return uninstall() end
  report('All options unticked — cleanup pending; resume the game to finish')
  return false
end
local function install()
  local ctx=context()
  if not ctx then tell('Enter a mission or skirmish and try again.'); return false end
  S.bound=ctx
  for _,kind in ipairs(hookOrder) do
    local ok,info=run(configs[S.game].scripts[kind])
    if not ok then
      uninstall()
      tell('This game code does not match the table, or another patch is already installed. Turn off other tables or mods and retry.')
      return false
    end
    S.installed[kind]=info
    local hook=getAddressSafe('cnc_'..kind..'_hook')
    local allocation=info and info.allocs and info.allocs['cnc_'..kind..'_code']
    local displacement=hook and readInteger(hook+1)
    if not allocation or not displacement or readBytes(hook,1)~=0xE9 or
      (hook+5+displacement)%0x100000000~=allocation.address then
      uninstall()
      tell('The game did not accept the patch. Turn off other tables and try MAIN again.')
      return false
    end
    info.hook=hook; info.patch={}; info.original={}
    local original=configs[S.game].scripts[kind]:match('%[DISABLE%]%s*[^\n]+:%s*db ([^\n]+)')
    for byte in original:gmatch('%x%x') do info.original[#info.original+1]=tonumber(byte,16) end
    for i=1,hookSizes[kind] do info.patch[i]=readBytes(hook+i-1,1) end
  end
  S.state=getAddressSafe('cnc_state')
  if not S.state then uninstall(); return false end
  for off,value in pairs({[0]=ctx.p,[4]=ctx.money,[8]=ctx.energy,[0x20]=ctx.frame,[0x24]=ctx.logic,[0x44]=ctx.shroud}) do
    if not write(off,value) then uninstall(); tell('The table could not prepare this match. Try activating MAIN again.'); return false end
  end
  if not write(0x1C,1) then uninstall(); return false end
  return true
end
-- Keep the existing hooks dormant while map objects are being replaced.
-- A new context must advance across two polls before its allowances are applied.
local function sameMatch(a,b)
  return a and b and a.p==b.p and a.money==b.money and a.energy==b.energy and
    a.logic==b.logic and a.shroud==b.shroud
end
local function resumeMatch()
  if not write(0x1C,0) then return false end
  S.transition=true
  local ctx=context()
  if not ctx then
    S.candidate=nil
    report('Selections saved - waiting for the next map')
    return false
  end
  local previousFrame=readInteger(S.state+0x20)
  local unchanged=sameMatch(ctx,S.bound) and previousFrame and ctx.frame&gt;=previousFrame
  if not unchanged and (not sameMatch(ctx,S.candidate) or ctx.frame&lt;=S.candidate.frame) then
    S.candidate=ctx
    report('Selections saved - waiting for the new map to run')
    return false
  end
  if not unchanged then
    -- Old resources belong to the previous map: never subtract from or restore them.
    for _,off in ipairs({0x10,0x18,0x38,0x40}) do if not write(off,0) then return false end end
    for off,value in pairs({[0]=ctx.p,[4]=ctx.money,[8]=ctx.energy,[0x20]=ctx.frame,
        [0x24]=ctx.logic,[0x44]=ctx.shroud}) do
      if not write(off,value) then return false end
    end
    S.bound=ctx
  end
  if not write(0x1C,1) then return false end
  S.transition=nil; S.candidate=nil
  report(configs[S.game].title..' | '..S.version..' | Selections active')
  return true
end
function S.poll(requested)
  forgetExitedProcess()
  if S.menu then
    if not getProcesslist()[S.menu.pid] then
      S.menu=nil; uncheck()
    elseif requested and requested~=S.menu.game then
      S.menu=nil; uncheck()
    else
      if getOpenedProcessID()~=S.menu.pid then
        report('Return to the selected game process or use Clear All'); return false
      end
      if not context() then report('Options selected - waiting for a mission or skirmish'); return true end
      local choices=S.menu.choices
      if not install() then S.menu=nil; uncheck(); return false end
      S.menu=nil
      for name,on in pairs(choices) do
        if on and not write(flagOffsets[name],1) then S.clear(); return false end
      end
      report(configs[S.game].title..' | '..S.version..' | Selections active')
      return true
    end
  end
  if S.state and S.stopping then
    if not S.clear() then return false end
  end
  if S.state then
    if getOpenedProcessID()~=S.pid then
      report('Return to the original game process and use Clear All before switching')
      return false
    end
    if requested and requested~=S.game then
      if not S.clear() then return false end
    elseif not owned() or readInteger(S.state+0x1C)==0 then
      return resumeMatch()
    else return true end
  end
  local found={}
  for pid,name in pairs(getProcesslist()) do
    for key,c in pairs(configs) do
      if baseName(name)==c.module and (not requested or key==requested) then found[#found+1]={pid=pid,key=key} end
    end
  end
  local selected
  for _,candidate in ipairs(found) do if candidate.pid==getOpenedProcessID() then selected=candidate; break end end
  if not selected and #found==1 then selected=found[1] end
  if not selected then
    if not requested then report(#found&gt;1 and 'Both games available — tick either MAIN' or 'Waiting for either game') end
    return false
  end
  local c=configs[selected.key]
  local module
  for _,m in ipairs(enumModules(selected.pid) or {}) do
    if baseName(m.PathToFile or m.Name)==c.module then module=m; break end
  end
  if not module then return false end
  if getOpenedProcessID()~=selected.pid then openProcess(selected.pid) end
  if getOpenedProcessID()~=selected.pid then return false end
  if S.pid~=selected.pid or S.game~=selected.key or S.base~=module.Address then
    local _,v=getFileVersion(module.PathToFile)
    S.version=v and string.format('%d.%d.%d.%d',v.major,v.minor,v.release,v.build) or 'Unknown'
    S.supported=S.version==c.version and md5file(module.PathToFile):lower()==c.hash
    S.pid=selected.pid; S.game=selected.key; S.base=module.Address
  end
  report(c.title..' | '..S.version..(S.supported and '' or ' | Unsupported build'))
  return true
end
local function excludeOtherReveal(game,name)
  if name~='visual' and name~='full' then return true end
  local other=name=='visual' and 'full' or 'visual'
  if S.menu then S.menu.choices[other]=false
  elseif not write(flagOffsets[other],0) then return false end
  suppress=true
  list.getMemoryRecordByID((game=='tw' and 10 or 20)+ids[other]).Active=false
  suppress=false
  return true
end
for key,main in pairs(mains) do
  local game=key
  main.OnActivate=function(_,before)
    if not before or suppress then return true end
    if S.closing then return false end
    if not S.poll(game) then
      tell(S.stopping and 'Resume the game to finish cleanup, then select the other MAIN.' or 'Start the matching game and try again.')
      return false
    end
    if not S.supported then tell("This table supports the installed Steam Tiberium Wars 1.10 and Kane's Wrath 1.3 builds. This executable is different; leave the options off."); return false end
    if S.state or S.menu then return true end
    if not context() then
      S.menu={game=game,pid=S.pid,choices={}}
      report('Options selected - waiting for a mission or skirmish')
      return true
    end
    return install()
  end
  main.OnDeactivate=function(_,before)
    if not before or suppress then return true end
    local complete=S.clear()
    return complete or S.offRequested==true
  end
  for feature,offset in pairs(ids) do
    local name=feature
    local record=list.getMemoryRecordByID((game=='tw' and 10 or 20)+offset)
    record.OnActivate=function(_,before)
      if not before or suppress then return true end
      if S.menu and S.menu.game==game and not S.closing then
        if not excludeOtherReveal(game,name) then return false end
        S.menu.choices[name]=true
        return true
      end
      if S.closing or S.game~=game or not S.state or S.stopping or (not S.transition and not owned()) then
        tell('Enable the matching MAIN in the current match first.'); return false
      end
      if not excludeOtherReveal(game,name) then return false end
      return write(flagOffsets[name],1)
    end
    record.OnDeactivate=function(_,before)
      if not before or suppress then return true end
      if S.menu and S.menu.game==game then S.menu.choices[name]=false; return true end
      return not S.state or write(flagOffsets[name],0)
    end
  end
end
-- Keep CE from presenting raw Lua exceptions from activation callbacks.
local function guarded(callback)
  return function(sender,before)
    local ok,result=pcall(callback,sender,before)
    if not ok then
      S.lastError=tostring(result)
      tell('The game could not be accessed. Use Clear All, then try again once the match is ready.')
      return false
    end
    return result
  end
end
for _,main in pairs(mains) do
  main.OnActivate=guarded(main.OnActivate)
  main.OnDeactivate=guarded(main.OnDeactivate)
  for i=0,main.Count-1 do
    local child=main.Child[i]
    child.OnActivate=guarded(child.OnActivate)
    child.OnDeactivate=guarded(child.OnDeactivate)
  end
end
function S.shutdown()
  if not S.clear() then return false end
  if S.timer then S.timer.destroy(); S.timer=nil end
  if S.closeToken then getMainForm().unregisterCloseCallback(S.closeToken); S.closeToken=nil end
  if not S.recordsRemoved then
    for _,main in pairs(mains) do
      main.OnActivate=nil; main.OnDeactivate=nil
      for i=0,main.Count-1 do main.Child[i].OnActivate=nil; main.Child[i].OnDeactivate=nil end
    end
  end
  return true
end
S.closeToken=getMainForm().registerCloseCallback(function(_,action)
  if action==caNone then return action end
  if not S.shutdown() then
    S.closing=true
    if S.offRequested then report('Closing after cleanup - resume the game if paused') end
    return caNone
  end
  return action
end)
S.timer=createTimer(getMainForm(),false)
S.timer.Interval=200
S.timer.OnTimer=function()
  if S.closing then
    local ok,complete=pcall(S.shutdown)
    if not ok then S.lastError=tostring(complete); report('Close pending - cleanup could not finish')
    elseif complete then
      S.closing=false
      createTimer(1,function() getMainForm().close() end)
    elseif S.offRequested then report('Closing after cleanup - resume the game if paused') end
    return
  end
  if getAddressList().getMemoryRecordByID(10)~=mains.tw then S.recordsRemoved=true; S.shutdown(); return end
  local ok,err=pcall(S.poll)
  if not ok then S.lastError=tostring(err); report('Unable to inspect game; use Clear All before continuing') end
end
S.timer.Enabled=true
S.timer.OnTimer()
</LuaScript>
</CheatTable>