Documentation progress

This commit is contained in:
MaddoScientisto 2026-04-08 00:03:10 +02:00
commit 5cc5612f4e
14 changed files with 244 additions and 814 deletions

View file

@ -3,816 +3,13 @@
<PROJECT_DATA_XML_NAME NAME="DISPLAY_DATA"> <PROJECT_DATA_XML_NAME NAME="DISPLAY_DATA">
<SAVE_STATE> <SAVE_STATE>
<ARRAY NAME="EXPANDED_PATHS" TYPE="string"> <ARRAY NAME="EXPANDED_PATHS" TYPE="string">
<A VALUE="Crusader:psx:" />
<A VALUE="Crusader:psx:remorse:" />
<A VALUE="Crusader:" /> <A VALUE="Crusader:" />
</ARRAY> </ARRAY>
<STATE NAME="SHOW_TABLE" TYPE="boolean" VALUE="false" /> <STATE NAME="SHOW_TABLE" TYPE="boolean" VALUE="false" />
</SAVE_STATE> </SAVE_STATE>
</PROJECT_DATA_XML_NAME> </PROJECT_DATA_XML_NAME>
<TOOL_MANAGER ACTIVE_WORKSPACE="Workspace"> <TOOL_MANAGER ACTIVE_WORKSPACE="Workspace">
<WORKSPACE NAME="Workspace" ACTIVE="true"> <WORKSPACE NAME="Workspace" ACTIVE="true" />
<RUNNING_TOOL TOOL_NAME="CodeBrowser">
<ROOT_NODE X_POS="-2" Y_POS="15" WIDTH="1381" HEIGHT="875" EX_STATE="0">
<SPLIT_NODE WIDTH="100" HEIGHT="100" DIVIDER_LOCATION="0" ORIENTATION="VERTICAL">
<SPLIT_NODE WIDTH="1866" HEIGHT="1014" DIVIDER_LOCATION="774" ORIENTATION="HORIZONTAL">
<SPLIT_NODE WIDTH="100" HEIGHT="100" DIVIDER_LOCATION="0" ORIENTATION="VERTICAL">
<SPLIT_NODE WIDTH="1866" HEIGHT="1014" DIVIDER_LOCATION="880" ORIENTATION="VERTICAL">
<SPLIT_NODE WIDTH="1866" HEIGHT="889" DIVIDER_LOCATION="863" ORIENTATION="VERTICAL">
<SPLIT_NODE WIDTH="100" HEIGHT="100" DIVIDER_LOCATION="0" ORIENTATION="VERTICAL">
<SPLIT_NODE WIDTH="1621" HEIGHT="816" DIVIDER_LOCATION="148" ORIENTATION="VERTICAL">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Entropy" OWNER="EntropyPlugin" TITLE="Entropy" ACTIVE="false" GROUP="Header" INSTANCE_ID="3207819926581772885" />
<COMPONENT_INFO NAME="Overview" OWNER="OverviewPlugin" TITLE="Overview" ACTIVE="false" GROUP="Header" INSTANCE_ID="3207819926581772883" />
</COMPONENT_NODE>
<SPLIT_NODE WIDTH="1367" HEIGHT="779" DIVIDER_LOCATION="174" ORIENTATION="HORIZONTAL">
<SPLIT_NODE WIDTH="237" HEIGHT="779" DIVIDER_LOCATION="640" ORIENTATION="VERTICAL">
<SPLIT_NODE WIDTH="237" HEIGHT="496" DIVIDER_LOCATION="502" ORIENTATION="VERTICAL">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Program Tree" OWNER="ProgramTreePlugin" TITLE="Program Trees" ACTIVE="true" GROUP="Default" INSTANCE_ID="3723604406647099771" />
</COMPONENT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Symbol Tree" OWNER="SymbolTreePlugin" TITLE="Symbol Tree" ACTIVE="true" GROUP="Default" INSTANCE_ID="3723604406647099766" />
</COMPONENT_NODE>
</SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="DataTypes Provider" OWNER="DataTypeManagerPlugin" TITLE="Data Type Manager" ACTIVE="true" GROUP="Default" INSTANCE_ID="3723604490275230076" />
</COMPONENT_NODE>
</SPLIT_NODE>
<SPLIT_NODE WIDTH="1126" HEIGHT="779" DIVIDER_LOCATION="785" ORIENTATION="VERTICAL">
<SPLIT_NODE WIDTH="1386" HEIGHT="638" DIVIDER_LOCATION="705" ORIENTATION="VERTICAL">
<SPLIT_NODE WIDTH="1126" HEIGHT="779" DIVIDER_LOCATION="490" ORIENTATION="HORIZONTAL">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Listing" OWNER="CodeBrowserPlugin" TITLE="Listing: SLUS_002.68" ACTIVE="true" GROUP="Core" INSTANCE_ID="3723604488515719525" />
</COMPONENT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Decompiler" OWNER="DecompilePlugin" TITLE="Decompile: psx_object_create_simple_record" ACTIVE="true" GROUP="Default" INSTANCE_ID="3723604406647099772" />
<COMPONENT_INFO NAME="Bytes" OWNER="ByteViewerPlugin" TITLE="Bytes: SLUS_002.68" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604406647099774" />
<COMPONENT_INFO NAME="Data Window" OWNER="DataWindowPlugin" TITLE="Defined Data" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604490583511403" />
<COMPONENT_INFO NAME="Defined Strings" OWNER="ViewStringsPlugin" TITLE="Defined Strings" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604490583511407" />
<COMPONENT_INFO NAME="Equates Table" OWNER="EquateTablePlugin" TITLE="Equates Table" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604488515719523" />
<COMPONENT_INFO NAME="External Programs" OWNER="ReferencesPlugin" TITLE="External Programs" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604488515719526" />
<COMPONENT_INFO NAME="Functions Window" OWNER="FunctionWindowPlugin" TITLE="Functions" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604488515719529" />
<COMPONENT_INFO NAME="Relocation Table" OWNER="RelocationTablePlugin" TITLE="Relocation Table" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604490583511406" />
</COMPONENT_NODE>
</SPLIT_NODE>
<SPLIT_NODE WIDTH="1386" HEIGHT="189" DIVIDER_LOCATION="495" ORIENTATION="HORIZONTAL">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Data Type Preview" OWNER="DataTypePreviewPlugin" TITLE="Data Type Preview" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604490008891766" />
</COMPONENT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Virtual Disassembler - Current Instruction" OWNER="DisassembledViewPlugin" TITLE="Disassembled View" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604488515719522" />
</COMPONENT_NODE>
</SPLIT_NODE>
</SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Console" OWNER="ConsolePlugin" TITLE="Console" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604406647099773" />
<COMPONENT_INFO NAME="Bookmarks" OWNER="BookmarkPlugin" TITLE="Bookmarks" ACTIVE="false" GROUP="Core.Bookmarks" INSTANCE_ID="3723604406647099770" />
</COMPONENT_NODE>
</SPLIT_NODE>
</SPLIT_NODE>
</SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Function Call Trees" OWNER="CallTreePlugin" TITLE="Function Call Trees" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604406647099767" />
</COMPONENT_NODE>
</SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Domain Events" OWNER="DomainEventDisplayPlugin" TITLE="Domain Object Event Display" ACTIVE="false" GROUP="Default" INSTANCE_ID="3722070732148365067" />
</COMPONENT_NODE>
</SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Plugin Event Display" OWNER="EventDisplayPlugin" TITLE="Plugin Event Display" ACTIVE="false" GROUP="Default" INSTANCE_ID="3722070732148365064" />
</COMPONENT_NODE>
</SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Database Viewer" OWNER="DbViewerPlugin" TITLE="Database Viewer" ACTIVE="false" GROUP="Default" INSTANCE_ID="3722070734440552208" />
</COMPONENT_NODE>
</SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Decompiler" OWNER="DecompilePlugin" TITLE="[Decompile: Weapon_GetDisplayFrameForShape]" ACTIVE="false" GROUP="disconnected" INSTANCE_ID="3721996248960424124" />
</COMPONENT_NODE>
</SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Diff Location Details" OWNER="ProgramDiffPlugin" TITLE="Diff Details" ACTIVE="false" GROUP="Default" INSTANCE_ID="3721161170088475892" />
</COMPONENT_NODE>
</SPLIT_NODE>
<WINDOW_NODE X_POS="426" Y_POS="178" WIDTH="1033" HEIGHT="689">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Script Manager" OWNER="GhidraScriptMgrPlugin" TITLE="Script Manager" ACTIVE="false" GROUP="Script Group" INSTANCE_ID="3723604406647099768" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="423" Y_POS="144" WIDTH="927" HEIGHT="695">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Memory Map" OWNER="MemoryMapPlugin" TITLE="Memory Map" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604406647099749" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="383" Y_POS="7" WIDTH="1020" HEIGHT="1038">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Function Graph" OWNER="FunctionGraphPlugin" TITLE="Function Graph" ACTIVE="false" GROUP="Function Graph" INSTANCE_ID="3723604490583511408" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="550" Y_POS="206" WIDTH="655" HEIGHT="509">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Register Manager" OWNER="RegisterPlugin" TITLE="Register Manager" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604488515719528" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="287" Y_POS="186" WIDTH="1424" HEIGHT="666">
<SPLIT_NODE WIDTH="1408" HEIGHT="559" DIVIDER_LOCATION="573" ORIENTATION="HORIZONTAL">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Symbol Table" OWNER="SymbolTablePlugin" TITLE="Symbol Table" ACTIVE="false" GROUP="symbolTable" INSTANCE_ID="3723604490583511404" />
</COMPONENT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Symbol References" OWNER="SymbolTablePlugin" TITLE="Symbol References" ACTIVE="false" GROUP="symbolTable" INSTANCE_ID="3723604490583511405" />
</COMPONENT_NODE>
</SPLIT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="-1" Y_POS="-1" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Checksum Generator" OWNER="ComputeChecksumsPlugin" TITLE="Checksum Generator" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604488515719524" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="-1" Y_POS="-1" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Function Tags" OWNER="FunctionTagPlugin" TITLE="Function Tags" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604490275230077" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="-1" Y_POS="-1" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Comment Window" OWNER="CommentWindowPlugin" TITLE="Comments" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604490583511402" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="-1" Y_POS="-1" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Python" OWNER="InterpreterPanelPlugin" TITLE="Python" ACTIVE="false" GROUP="Default" INSTANCE_ID="3207819978370941531" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Jython" OWNER="Jython" TITLE="Jython" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604490275230078" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Bundle Manager" OWNER="GhidraScriptMgrPlugin" TITLE="Bundle Manager" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604406647099769" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="PyGhidra" OWNER="PyGhidra" TITLE="PyGhidra" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604490583511401" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Source Files and Transforms" OWNER="SourceFilesTablePlugin" TITLE="Source Files and Transforms" ACTIVE="false" GROUP="Default" INSTANCE_ID="3723604488515719527" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Function Call Graph" OWNER="FunctionCallGraphPlugin" TITLE="Function Call Graph" ACTIVE="false" GROUP="Function Call Graph" INSTANCE_ID="3723604490008891767" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="588" Y_POS="50" WIDTH="1018" HEIGHT="1087">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Graph" OWNER="DefaultGraphDisplay" TITLE="AST Data Flow Graph For entity_state_tick_dispatch" ACTIVE="false" GROUP="ProgramGraph" INSTANCE_ID="3720233517670421199" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Window Locations" OWNER="WindowLocationPlugin" TITLE="Window Locations" ACTIVE="false" GROUP="Default" INSTANCE_ID="3722070719626270492" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="890" Y_POS="456" WIDTH="729" HEIGHT="566">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Location References Provider" OWNER="LocationReferencesPlugin" TITLE="References to g_jassica16Offset - 7 locations" ACTIVE="false" GROUP="Default" INSTANCE_ID="3721161260863700211" />
</COMPONENT_NODE>
</WINDOW_NODE>
</ROOT_NODE>
<DATA_STATE>
<PLUGIN NAME="NavigationHistoryPlugin">
<XML NAME="HISTORY_LIST_0">
<SAVE_STATE>
<STATE NAME="CURRENT_LOC_INDEX" TYPE="int" VALUE="9" />
<STATE NAME="LOCATION_COUNT" TYPE="int" VALUE="10" />
<STATE NAME="MEMENTO_CLASS0" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="MEMENTO_CLASS1" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="MEMENTO_CLASS2" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="MEMENTO_CLASS3" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="MEMENTO_CLASS4" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="MEMENTO_CLASS5" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="MEMENTO_CLASS6" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="MEMENTO_CLASS7" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="MEMENTO_CLASS8" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="MEMENTO_CLASS9" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<XML NAME="MEMENTO_DATA0">
<SAVE_STATE>
<XML NAME="MEMENTO0">
<SAVE_STATE>
<STATE NAME="CURSOR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.codebrowser.CodeViewerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604488515719525" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="1f800000" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="1f800000" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.MemoryBlockStartFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<ARRAY NAME="_COMMENT" TYPE="string">
<A VALUE="//" />
<A VALUE="// CACHE" />
<A VALUE="// ram:1f800000-ram:1f8003ff" />
<A VALUE="//" />
</ARRAY>
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_TYPE" TYPE="int" VALUE="-1" />
</SAVE_STATE>
</XML>
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="NUM_MEMENTOS" TYPE="int" VALUE="1" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="8002b3d4" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="8002b3d4" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="8002b3d4" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined main()" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO_DATA1">
<SAVE_STATE>
<XML NAME="MEMENTO0">
<SAVE_STATE>
<STATE NAME="CURSOR_OFFSET" TYPE="int" VALUE="400" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.codebrowser.CodeViewerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604488515719525" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="8002b3d4" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="8002b3d4" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="8002b3d4" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined main()" />
</SAVE_STATE>
</XML>
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="NUM_MEMENTOS" TYPE="int" VALUE="1" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="1f800000" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="1f800000" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.MemoryBlockStartFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<ARRAY NAME="_COMMENT" TYPE="string">
<A VALUE="//" />
<A VALUE="// CACHE" />
<A VALUE="// ram:1f800000-ram:1f8003ff" />
<A VALUE="//" />
</ARRAY>
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_TYPE" TYPE="int" VALUE="-1" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO_DATA2">
<SAVE_STATE>
<XML NAME="MEMENTO0">
<SAVE_STATE>
<STATE NAME="INDEX" TYPE="int" VALUE="0" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.decompile.DecompilerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604406647099772" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="X_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="Y_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80045ffc" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80045ffc" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="80045ffc" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined psx_cache_type_art_descriptor()" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO1">
<SAVE_STATE>
<STATE NAME="CURSOR_OFFSET" TYPE="int" VALUE="400" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.codebrowser.CodeViewerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604488515719525" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80045ffc" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80045ffc" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="80045ffc" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined psx_cache_type_art_descriptor()" />
</SAVE_STATE>
</XML>
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="NUM_MEMENTOS" TYPE="int" VALUE="2" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80045ffc" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80045ffc" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="80045ffc" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined psx_cache_type_art_descriptor()" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO_DATA3">
<SAVE_STATE>
<XML NAME="MEMENTO0">
<SAVE_STATE>
<STATE NAME="INDEX" TYPE="int" VALUE="0" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.decompile.DecompilerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604406647099772" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="X_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="Y_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80011ef8" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80011ef8" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="80011ef8" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined FUN_80011ef8()" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO1">
<SAVE_STATE>
<STATE NAME="CURSOR_OFFSET" TYPE="int" VALUE="369" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.codebrowser.CodeViewerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604488515719525" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80011ef8" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80011ef8" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="80011ef8" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined FUN_80011ef8()" />
</SAVE_STATE>
</XML>
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="NUM_MEMENTOS" TYPE="int" VALUE="2" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80011ef8" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80011ef8" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="80011ef8" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined FUN_80011ef8()" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO_DATA4">
<SAVE_STATE>
<XML NAME="MEMENTO0">
<SAVE_STATE>
<STATE NAME="INDEX" TYPE="int" VALUE="0" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.decompile.DecompilerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604406647099772" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="X_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="Y_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80012138" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80012138" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="80012138" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined FUN_80012138()" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO1">
<SAVE_STATE>
<STATE NAME="CURSOR_OFFSET" TYPE="int" VALUE="369" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.codebrowser.CodeViewerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604488515719525" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80012138" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80012138" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="80012138" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined FUN_80012138()" />
</SAVE_STATE>
</XML>
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="NUM_MEMENTOS" TYPE="int" VALUE="2" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80012138" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80012138" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="80012138" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined FUN_80012138()" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO_DATA5">
<SAVE_STATE>
<XML NAME="MEMENTO0">
<SAVE_STATE>
<STATE NAME="INDEX" TYPE="int" VALUE="0" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.decompile.DecompilerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604406647099772" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="X_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="Y_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80012138" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80012138" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="80012138" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined FUN_80012138()" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO1">
<SAVE_STATE>
<STATE NAME="CURSOR_OFFSET" TYPE="int" VALUE="369" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.codebrowser.CodeViewerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604488515719525" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80012538" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80012538" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="80012538" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined FUN_80012538()" />
</SAVE_STATE>
</XML>
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="NUM_MEMENTOS" TYPE="int" VALUE="2" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80012538" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80012538" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.FunctionReturnTypeFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNC_ADDRESS" TYPE="string" VALUE="80012538" />
<STATE NAME="_RETURN_TYPE" TYPE="string" VALUE="undefined" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_SIGNATURE" TYPE="string" VALUE="undefined FUN_80012538()" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO_DATA6">
<SAVE_STATE>
<XML NAME="MEMENTO0">
<SAVE_STATE>
<STATE NAME="INDEX" TYPE="int" VALUE="0" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.decompile.DecompilerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604406647099772" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="X_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="Y_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80012538" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80012538" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CHAR_POS" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.app.decompiler.location.DefaultDecompilerLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNCTION_ENTRY" TYPE="string" VALUE="80012538" />
<STATE NAME="_LINE_NUM" TYPE="int" VALUE="0" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_TOKEN_TEXT" TYPE="string" VALUE="" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO1">
<SAVE_STATE>
<STATE NAME="CURSOR_OFFSET" TYPE="int" VALUE="639" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.codebrowser.CodeViewerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604488515719525" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80012538" />
<STATE NAME="_ADDR_REP" TYPE="string" VALUE="80012538" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80012538" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.AddressFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
</SAVE_STATE>
</XML>
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="NUM_MEMENTOS" TYPE="int" VALUE="2" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80012538" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80012538" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CHAR_POS" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.app.decompiler.location.DefaultDecompilerLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNCTION_ENTRY" TYPE="string" VALUE="80012538" />
<STATE NAME="_LINE_NUM" TYPE="int" VALUE="0" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_TOKEN_TEXT" TYPE="string" VALUE="" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO_DATA7">
<SAVE_STATE>
<XML NAME="MEMENTO0">
<SAVE_STATE>
<STATE NAME="INDEX" TYPE="int" VALUE="0" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.decompile.DecompilerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604406647099772" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="X_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="Y_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80012538" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80012538" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CHAR_POS" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.app.decompiler.location.DefaultDecompilerLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNCTION_ENTRY" TYPE="string" VALUE="80012538" />
<STATE NAME="_LINE_NUM" TYPE="int" VALUE="0" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_TOKEN_TEXT" TYPE="string" VALUE="" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO1">
<SAVE_STATE>
<STATE NAME="CURSOR_OFFSET" TYPE="int" VALUE="369" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.codebrowser.CodeViewerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604488515719525" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="800249f4" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="800249f4" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.CommentFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<ARRAY NAME="_COMMENT" TYPE="string">
<A VALUE="Section-0 object constructor for the simpler record layout. Resolves DAT_800758d8 and DAT_800758d0 by type id, copies authored x/y/z into obj+0x3c/+0x40/+0x44 as 16.16 fixed-point, then seeds the object state/render path." />
</ARRAY>
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_TYPE" TYPE="int" VALUE="1" />
</SAVE_STATE>
</XML>
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="NUM_MEMENTOS" TYPE="int" VALUE="2" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="800249f4" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="800249f4" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="69" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.CommentFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<ARRAY NAME="_COMMENT" TYPE="string">
<A VALUE="Section-0 object constructor for the simpler record layout. Resolves DAT_800758d8 and DAT_800758d0 by type id, copies authored x/y/z into obj+0x3c/+0x40/+0x44 as 16.16 fixed-point, then seeds the object state/render path." />
</ARRAY>
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_TYPE" TYPE="int" VALUE="1" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO_DATA8">
<SAVE_STATE>
<STATE NAME="FOCUSED_NAV" TYPE="long" VALUE="3723604406647099772" />
<XML NAME="MEMENTO0">
<SAVE_STATE>
<STATE NAME="INDEX" TYPE="int" VALUE="0" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.decompile.DecompilerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604406647099772" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="X_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="Y_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="800249f4" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="800249f4" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CHAR_POS" TYPE="int" VALUE="14" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.app.decompiler.location.DefaultDecompilerLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNCTION_ENTRY" TYPE="string" VALUE="800249f4" />
<STATE NAME="_LINE_NUM" TYPE="int" VALUE="20" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_TOKEN_TEXT" TYPE="string" VALUE="DAT_80067814" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO1">
<SAVE_STATE>
<STATE NAME="CURSOR_OFFSET" TYPE="int" VALUE="45" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.codebrowser.CodeViewerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604488515719525" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="800249f4" />
<STATE NAME="_ADDR_REP" TYPE="string" VALUE="800249f4" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="800249f4" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.AddressFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
</SAVE_STATE>
</XML>
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="NUM_MEMENTOS" TYPE="int" VALUE="2" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="800249f4" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="800249f4" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CHAR_POS" TYPE="int" VALUE="14" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.app.decompiler.location.DefaultDecompilerLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNCTION_ENTRY" TYPE="string" VALUE="800249f4" />
<STATE NAME="_LINE_NUM" TYPE="int" VALUE="20" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_TOKEN_TEXT" TYPE="string" VALUE="DAT_80067814" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO_DATA9">
<SAVE_STATE>
<STATE NAME="FOCUSED_NAV" TYPE="long" VALUE="3723604406647099772" />
<XML NAME="MEMENTO0">
<SAVE_STATE>
<STATE NAME="INDEX" TYPE="int" VALUE="0" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.decompile.DecompilerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604406647099772" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="X_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="Y_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="800249f4" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="800249f4" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CHAR_POS" TYPE="int" VALUE="14" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.app.decompiler.location.DefaultDecompilerLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNCTION_ENTRY" TYPE="string" VALUE="800249f4" />
<STATE NAME="_LINE_NUM" TYPE="int" VALUE="20" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_TOKEN_TEXT" TYPE="string" VALUE="DAT_80067814" />
</SAVE_STATE>
</XML>
<XML NAME="MEMENTO1">
<SAVE_STATE>
<STATE NAME="CURSOR_OFFSET" TYPE="int" VALUE="369" />
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.codebrowser.CodeViewerLocationMemento" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604488515719525" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80067814" />
<STATE NAME="_ADDR_REP" TYPE="string" VALUE="80067814" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80067814" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.AddressFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<ARRAY NAME="_COMP_PATH" TYPE="int" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
</SAVE_STATE>
</XML>
<STATE NAME="MEMENTO_CLASS" TYPE="string" VALUE="ghidra.app.plugin.core.gotoquery.DefaultNavigatableLocationMemento" />
<STATE NAME="NUM_MEMENTOS" TYPE="int" VALUE="2" />
<STATE NAME="PROGRAM_ID" TYPE="long" VALUE="3722017627685836549" />
<STATE NAME="PROGRAM_PATH_" TYPE="string" VALUE="Crusader:/psx/remorse/SLUS_002.68" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80067814" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80067814" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.ProgramLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
</SAVE_STATE>
</XML>
<STATE NAME="NAV_ID" TYPE="long" VALUE="-1" />
</SAVE_STATE>
</XML>
<STATE NAME="LIST_COUNT" TYPE="int" VALUE="1" />
</PLUGIN>
<PLUGIN NAME="ProgramTreePlugin">
<STATE NAME="Current Viewname" TYPE="string" VALUE="Program Tree" />
<ARRAY NAME="GroupNameProgram Tree0" TYPE="string">
<A VALUE="SLUS_002.68" />
</ARRAY>
<STATE NAME="NavigationToggleState" TYPE="boolean" VALUE="false" />
<STATE NAME="NumberOfGroupsProgram Tree" TYPE="int" VALUE="1" />
<STATE NAME="NumberOfViews" TYPE="int" VALUE="1" />
<STATE NAME="TreeName-0" TYPE="string" VALUE="Program Tree" />
</PLUGIN>
<PLUGIN NAME="DecompilePlugin">
<STATE NAME="INDEX" TYPE="int" VALUE="0" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604406647099772" />
<STATE NAME="Num Disconnected" TYPE="int" VALUE="0" />
<STATE NAME="Y_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="800249f4" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="800249f4" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CHAR_POS" TYPE="int" VALUE="14" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.app.decompiler.location.DefaultDecompilerLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="0" />
<STATE NAME="_FUNCTION_ENTRY" TYPE="string" VALUE="800249f4" />
<STATE NAME="_LINE_NUM" TYPE="int" VALUE="20" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
<STATE NAME="_TOKEN_TEXT" TYPE="string" VALUE="DAT_80067814" />
</PLUGIN>
<PLUGIN NAME="ByteViewerPlugin">
<STATE NAME="Block Column" TYPE="int" VALUE="0" />
<STATE NAME="Block Num" TYPE="int" VALUE="0" />
<STATE NAME="Block Offset" TYPE="string" VALUE="0" />
<STATE NAME="Index" TYPE="int" VALUE="0" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604406647099774" />
<STATE NAME="Num Disconnected" TYPE="int" VALUE="0" />
<STATE NAME="X Offset" TYPE="int" VALUE="0" />
<STATE NAME="Y Offset" TYPE="int" VALUE="0" />
</PLUGIN>
<PLUGIN NAME="ProgramManagerPlugin">
<STATE NAME="CURRENT_FILE" TYPE="string" VALUE="SLUS_002.68" />
<STATE NAME="LOCATION_0" TYPE="string" VALUE="/D:/Ghidra/Crusader/" />
<STATE NAME="NUM_PROGRAMS" TYPE="int" VALUE="1" />
<STATE NAME="PATHNAME_0" TYPE="string" VALUE="/psx/remorse/SLUS_002.68" />
<STATE NAME="PROJECT_NAME_0" TYPE="string" VALUE="Crusader" />
<STATE NAME="VERSION_0" TYPE="int" VALUE="-1" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80067814" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80067814" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.XRefFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="6" />
<ARRAY NAME="_COMP_PATH" TYPE="int" />
<STATE NAME="_REF_ADDRESS" TYPE="string" VALUE="800255b8" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
</PLUGIN>
<PLUGIN NAME="FunctionGraphPlugin">
<SAVE_STATE NAME="COMPLEX_LAYOUT_NAME" TYPE="SaveState">
<COMPLEX_LAYOUT_NAME>
<STATE NAME="LAYOUT_CLASS_NAME" TYPE="string" VALUE="ghidra.app.plugin.core.functiongraph.graph.layout.DecompilerNestedLayoutProvider" />
<STATE NAME="LAYOUT_NAME" TYPE="string" VALUE="Nested Code Layout" />
</COMPLEX_LAYOUT_NAME>
</SAVE_STATE>
<STATE NAME="DISPLAY_POPUPS" TYPE="boolean" VALUE="true" />
<STATE NAME="DISPLAY_SATELLITE" TYPE="boolean" VALUE="true" />
<STATE NAME="DOCK_SATELLITE" TYPE="boolean" VALUE="true" />
<STATE NAME="DOCK_SATELLITE_POSITION" TYPE="string" VALUE="LOWER_RIGHT" />
<STATE NAME="Disconnected Count" TYPE="int" VALUE="0" />
<ENUM NAME="EDGE_HOVER_HIGHLIGHT" TYPE="enum" CLASS="ghidra.app.plugin.core.functiongraph.EdgeDisplayType" VALUE="ScopedFlowsFromVertex" />
<ENUM NAME="EDGE_SELECTION_HIGHLIGHT" TYPE="enum" CLASS="ghidra.app.plugin.core.functiongraph.EdgeDisplayType" VALUE="AllCycles" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604490583511408" />
</PLUGIN>
<PLUGIN NAME="CodeBrowserPlugin">
<STATE NAME="INDEX" TYPE="int" VALUE="429346" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3723604488515719525" />
<STATE NAME="Num Disconnected" TYPE="int" VALUE="0" />
<STATE NAME="Y_OFFSET" TYPE="int" VALUE="-225" />
<STATE NAME="_ADDRESS" TYPE="string" VALUE="80067814" />
<STATE NAME="_BYTE_ADDR" TYPE="string" VALUE="80067814" />
<STATE NAME="_CHAR_OFFSET" TYPE="int" VALUE="0" />
<STATE NAME="_CLASSNAME" TYPE="string" VALUE="ghidra.program.util.XRefFieldLocation" />
<STATE NAME="_COLUMN" TYPE="int" VALUE="6" />
<ARRAY NAME="_COMP_PATH" TYPE="int" />
<STATE NAME="_REF_ADDRESS" TYPE="string" VALUE="800255b8" />
<STATE NAME="_ROW" TYPE="int" VALUE="0" />
</PLUGIN>
</DATA_STATE>
</RUNNING_TOOL>
</WORKSPACE>
</TOOL_MANAGER> </TOOL_MANAGER>
</PROJECT> </PROJECT>

View file

@ -30,6 +30,8 @@ Recent verified Japanese-build follow-up: [docs/jp-remorse-cheats-and-launch-par
Recent verified localized-build batch: [docs/spanish-cheat-differences.md](docs/spanish-cheat-differences.md) now records a tighter live-Ghidra comparison against `/es/CRUSADER.EXE` for the known cheat/debug control areas. Current best read is now narrower than the earlier "moved matcher" theory: the Spanish executable still preserves the same broad cheat/debug framework as the English build with relocated addresses rather than different behavior, but it does **not** preserve the English `jassica16` table as the same static data object and this pass also failed to recover any replacement compiled matcher or any translated `~` cheat-latch toggle. The `-laurie` parser still sets the broad cheat/debug gate (`1478:0910`), the gameplay-input gate still exists at `1478:0927`, and Hack Mover still toggles through `13e8:24a5`; but the old English-side slot at `1478:2833` now contains pointer-like words, the old English immortality-string slots at `1478:2850/2866` are also repurposed as non-string data in Spanish, `1478:0910` has only the `-laurie` write at `1050:0985`, `1478:5fb3` only has the Laurie-hint helper writes at `13e8:0071/0077`, `World_HandleKeyboardInput` does not expose a recovered `0x7e` / tilde branch, and `1478:8ad6` still has no recovered writer even though Hack Mover checks it. The new keyboard-side conclusion is stronger too: `1478:5fb3` does not act like a live positive enable latch in Spanish, because every recovered consumer requires it to be zero and the Laurie-hint helper pulses it back to zero immediately, while the nearby `8ad7/8ad8/8ad9` runtime-state writes still do not explain `8ad6`. The Hack Mover runtime chain is also tighter now: `1478:5fb2` is the actual on/off toggle, `13e8:0ef9` / `13e8:0f77` clear it, `13e8:282f` is the adjacent runtime helper using `1478:8ad9`, and `13e8:2f0e` / `13e8:3009` bracket the active drag state via `1478:8ac0`, `1478:8acc`, and `1478:8ace`. Current safest localized-build read is therefore `-laurie is the only recovered positive enabler for the surviving broad Spanish cheat/debug family; no replacement hidden matcher, no runtime keyboard-latch bootstrap, and no direct Spanish F10 cheat branch have been recovered`, with the remaining open question narrowed to whether `1478:8ad6` is written through an analysis-dark path or is just a dead leftover gate. Recent verified localized-build batch: [docs/spanish-cheat-differences.md](docs/spanish-cheat-differences.md) now records a tighter live-Ghidra comparison against `/es/CRUSADER.EXE` for the known cheat/debug control areas. Current best read is now narrower than the earlier "moved matcher" theory: the Spanish executable still preserves the same broad cheat/debug framework as the English build with relocated addresses rather than different behavior, but it does **not** preserve the English `jassica16` table as the same static data object and this pass also failed to recover any replacement compiled matcher or any translated `~` cheat-latch toggle. The `-laurie` parser still sets the broad cheat/debug gate (`1478:0910`), the gameplay-input gate still exists at `1478:0927`, and Hack Mover still toggles through `13e8:24a5`; but the old English-side slot at `1478:2833` now contains pointer-like words, the old English immortality-string slots at `1478:2850/2866` are also repurposed as non-string data in Spanish, `1478:0910` has only the `-laurie` write at `1050:0985`, `1478:5fb3` only has the Laurie-hint helper writes at `13e8:0071/0077`, `World_HandleKeyboardInput` does not expose a recovered `0x7e` / tilde branch, and `1478:8ad6` still has no recovered writer even though Hack Mover checks it. The new keyboard-side conclusion is stronger too: `1478:5fb3` does not act like a live positive enable latch in Spanish, because every recovered consumer requires it to be zero and the Laurie-hint helper pulses it back to zero immediately, while the nearby `8ad7/8ad8/8ad9` runtime-state writes still do not explain `8ad6`. The Hack Mover runtime chain is also tighter now: `1478:5fb2` is the actual on/off toggle, `13e8:0ef9` / `13e8:0f77` clear it, `13e8:282f` is the adjacent runtime helper using `1478:8ad9`, and `13e8:2f0e` / `13e8:3009` bracket the active drag state via `1478:8ac0`, `1478:8acc`, and `1478:8ace`. Current safest localized-build read is therefore `-laurie is the only recovered positive enabler for the surviving broad Spanish cheat/debug family; no replacement hidden matcher, no runtime keyboard-latch bootstrap, and no direct Spanish F10 cheat branch have been recovered`, with the remaining open question narrowed to whether `1478:8ad6` is written through an analysis-dark path or is just a dead leftover gate.
Recent startup fixed-map patch batch: [docs/startup-map-patch-file.md](docs/startup-map-patch-file.md) now records the current evidence-backed read of the retail `Using map patch file.` startup line. Current best read is that `Init_Everything` at `1048:039b` prints that line only if `static\fixed.dat` exists, and the later fixed-map loader path treats that file as a preferred alternate `FIXED.DAT` source by loading it into `DAT_1478_1064` and choosing that handle over the base archive handle when present. The safest current wording is therefore `alternate fixed-map archive selected at startup`, not `the -u usecode override` and not a proven per-record merge overlay.
Recent verified batch: [docs/retail-debug-arg.md](docs/retail-debug-arg.md) now records the live NE proof that retail `CRUSADER.EXE` still recognizes and executes a real `-debug` command-line branch. That branch prints `Debugging mode ON.`, sets `g_debugMsgLevel` at `1478:87e0`, and toggles two debug globals at `1478:0845/0859`. The later sink pass also closes the text-output target more tightly: `ProbablyPrintDebugMessage` formats through the static stdio-style table at `1478:6c32..6c81` and writes to the handle-`1` entry at `1478:6c46`, so the non-video side is ordinary DOS `stdout` gated by the debug threshold, plus the already-confirmed AVI timing overlay. Current best read remains `surviving debug-output / instrumentation switch`, not `the missing bootstrap for the hidden seg109/seg1408 usecode debugger`. The same batch also leaves the earlier `-laurie` and `0x659c/659e` debugger-state conclusions intact: `-debug` is a separate switch and is not currently evidenced as constructing the hidden usecode-debugger break-state object. Recent verified batch: [docs/retail-debug-arg.md](docs/retail-debug-arg.md) now records the live NE proof that retail `CRUSADER.EXE` still recognizes and executes a real `-debug` command-line branch. That branch prints `Debugging mode ON.`, sets `g_debugMsgLevel` at `1478:87e0`, and toggles two debug globals at `1478:0845/0859`. The later sink pass also closes the text-output target more tightly: `ProbablyPrintDebugMessage` formats through the static stdio-style table at `1478:6c32..6c81` and writes to the handle-`1` entry at `1478:6c46`, so the non-video side is ordinary DOS `stdout` gated by the debug threshold, plus the already-confirmed AVI timing overlay. Current best read remains `surviving debug-output / instrumentation switch`, not `the missing bootstrap for the hidden seg109/seg1408 usecode debugger`. The same batch also leaves the earlier `-laurie` and `0x659c/659e` debugger-state conclusions intact: `-debug` is a separate switch and is not currently evidenced as constructing the hidden usecode-debugger break-state object.
Recent tooling batch: [docs/map-rendering.md](docs/map-rendering.md) now starts a dedicated offline map-rendering lane. `tools/render_crusader_map.py` can load `FIXED.DAT`, expand `GLOB.FLX`, decode the required `SHAPES.FLX` entries with Crusader frame headers, apply `GAMEPAL.PAL`, and write a first-pass PNG, with a `--fixed-dat` override so the same pipeline can be pointed at either game's map file. The current renderer is intentionally limited to fixed-map content and a simple deterministic painter rather than the full Pentagram/ScummVM dependency sorter, and the current workspace caveat is that `STATIC_REGRET` still lacks a copied `FIXED.DAT`, so No Regret rendering needs that file supplied explicitly. Recent tooling batch: [docs/map-rendering.md](docs/map-rendering.md) now starts a dedicated offline map-rendering lane. `tools/render_crusader_map.py` can load `FIXED.DAT`, expand `GLOB.FLX`, decode the required `SHAPES.FLX` entries with Crusader frame headers, apply `GAMEPAL.PAL`, and write a first-pass PNG, with a `--fixed-dat` override so the same pipeline can be pointed at either game's map file. The current renderer is intentionally limited to fixed-map content and a simple deterministic painter rather than the full Pentagram/ScummVM dependency sorter, and the current workspace caveat is that `STATIC_REGRET` still lacks a copied `FIXED.DAT`, so No Regret rendering needs that file supplied explicitly.
@ -94,6 +96,7 @@ Latest F7 overlay follow-up: new note [docs/f7-overlays.md](docs/f7-overlays.md)
| [docs/ne-hole-filling-priorities.md](docs/ne-hole-filling-priorities.md) | Ranked `CRUSADER.EXE` hole-filling tracker: NE-side unclear lanes, the verified raw-side knowledge that can close them, and the recommended order for old-to-new porting passes | | [docs/ne-hole-filling-priorities.md](docs/ne-hole-filling-priorities.md) | Ranked `CRUSADER.EXE` hole-filling tracker: NE-side unclear lanes, the verified raw-side knowledge that can close them, and the recommended order for old-to-new porting passes |
| [docs/retail-debugger-patch-attempts.md](docs/retail-debugger-patch-attempts.md) | Chronological log of retail `CRUSADER.EXE` debugger-unlock patch attempts, byte-level designs, runtime failures, root-cause findings, and the current live candidate | | [docs/retail-debugger-patch-attempts.md](docs/retail-debugger-patch-attempts.md) | Chronological log of retail `CRUSADER.EXE` debugger-unlock patch attempts, byte-level designs, runtime failures, root-cause findings, and the current live candidate |
| [docs/retail-debug-arg.md](docs/retail-debug-arg.md) | Focused note on the retail `-debug` command-line switch: live parser evidence, exact startup message, surviving globals, segment `1468` instrumentation path, and why it is currently separate from the hidden usecode debugger bootstrap | | [docs/retail-debug-arg.md](docs/retail-debug-arg.md) | Focused note on the retail `-debug` command-line switch: live parser evidence, exact startup message, surviving globals, segment `1468` instrumentation path, and why it is currently separate from the hidden usecode debugger bootstrap |
| [docs/startup-map-patch-file.md](docs/startup-map-patch-file.md) | Focused note on the retail `Using map patch file.` startup line: exact `Init_Everything` print gate, `static\fixed.dat` detection, the later `ItemCache_InitAndLoadFixedDat` archive load, and the current evidence that fixed-map reads prefer the alternate archive when present |
| [docs/remorse-class-candidate-inventory.md](docs/remorse-class-candidate-inventory.md) | Evidence-backed inventory of the strongest current Remorse class families, with confidence, ctor/dtor/vtable/layout anchors, and recommended modeling order for later Ghidra class work | | [docs/remorse-class-candidate-inventory.md](docs/remorse-class-candidate-inventory.md) | Evidence-backed inventory of the strongest current Remorse class families, with confidence, ctor/dtor/vtable/layout anchors, and recommended modeling order for later Ghidra class work |
| [docs/remorse-class-lift-index.md](docs/remorse-class-lift-index.md) | Central navigation note for the Remorse class-lift and C++-reconstruction prep lane, grouping the plan, candidate inventory, ABI notes, endpoint spec, and family-specific layout notes into one work order | | [docs/remorse-class-lift-index.md](docs/remorse-class-lift-index.md) | Central navigation note for the Remorse class-lift and C++-reconstruction prep lane, grouping the plan, candidate inventory, ABI notes, endpoint spec, and family-specific layout notes into one work order |
| [docs/remorse-first-class-authoring-checklist.md](docs/remorse-first-class-authoring-checklist.md) | Operational checklist for the first real Ghidra/MCP class-authoring batch, including pilot-family order, authoring rules, and source-emission readiness gates | | [docs/remorse-first-class-authoring-checklist.md](docs/remorse-first-class-authoring-checklist.md) | Operational checklist for the first real Ghidra/MCP class-authoring batch, including pilot-family order, authoring rules, and source-emission readiness gates |

View file

@ -232,8 +232,57 @@ When manual class work starts, the safest order for this family is:
Do not start by forcing one complete 0x520-byte monolithic class. Do not start by forcing one complete 0x520-byte monolithic class.
## Live Ghidra Authoring Status
Verified first live `EntityDispatchEntry` shell batch landed on 2026-04-07.
- Created class owner `Remorse::EntityDispatchEntry` in the active `CRUSADER.EXE` database.
- Created provisional base datatype `/Remorse/EntityDispatchEntryBase` with the current stable field block through `+0x18`:
- `type_or_kind`
- `slot_index_or_count`
- `source_type`
- `event_type_or_list_ptr_lo`
- `group_id_byte`
- `link_or_state_word_0a..10`
- `target_farptr`
- `flags1`
- `flags2`
- Created provisional vtable datatype `/Remorse/EntityDispatchEntryVtable` with only the two currently verified callback slots exposed:
- `+0x14 = update_callback_slot14`
- `+0x28 = dispatch_callback_slot28`
- Kept the remaining vtable lanes explicit as unresolved padding instead of inventing slot names too early.
- Did not move methods yet. The current source note still anchors this family through the older `0008:` / `000d:` address notation, and those entrypoints are not yet mapped into the active live `CRUSADER.EXE` session strongly enough to justify owner moves by guesswork.
- The current live MCP `apply_class_layout(...)` path also rejected the minimal shell bind with an undocumented required `methods` property, so this first shell pass used the now-working live `run_write_script(...)` fallback to author the class namespace and datatypes directly.
This means the family is now started in-session rather than remaining note-only, but it is still in the pre-method phase.
That is no longer true after the next live pass on 2026-04-07.
- The older `0008:ba00` pilot cluster is now re-anchored in the live `CRUSADER.EXE` session as the `11e0:` process-substrate segment by direct offset mapping from the decompiler's embedded original-segment metadata.
- The first strong base-method batch is now moved under `Remorse::EntityDispatchEntry`:
- `11e0:0000` -> `InitBase` (older note anchor `0008:ba00`)
- `11e0:01b6` -> `SetSourceType` (older note anchor `0008:bbb6`)
- `11e0:0227` -> `SetEventTypeChecked` (older note anchor `0008:bc27`)
- `11e0:02a8` -> `SetGroupId` (older note anchor `0008:bca8`)
- `11e0:0353` -> `Unlink` (older note anchor `0008:bd53`)
- `11e0:0405` -> `IncrementGroupId` (older note anchor `0008:be05`)
- Those six methods now carry provisional `EntityDispatchEntryBase * this` signatures in-session plus decompiler comments recording the old `0008:` provenance so later note cleanup does not have to re-derive the mapping.
- The current live surface is still deliberately conservative. The decompiler still shows the underlying `struct_Process` substrate in several bodies, so this batch should be treated as class ownership plus field-layout alignment, not proof that every inherited process-style helper name is final.
- The next derived-family batch is now landed too. The older runtime-state pair from the note's `000d:` anchors is re-anchored in the live `1440:` fade/palette cluster by explicit decompiler segment metadata and matching offset delta:
- `1440:0000 FadeProcess_Create` -> `Remorse::EntityDispatchEntry::InitRuntimeState` (older note anchor `000d:7e00`)
- `1440:0278 FUN_1440_0278` -> `Remorse::EntityDispatchEntry::ReleaseRuntimeState` (older note anchor `000d:8078`)
- Created `/Remorse/EntityDispatchEntryRuntimeState` as a provisional overlay datatype. It preserves the stable base block through `+0x18`, keeps `+0x1a..+0x3f` explicit as unresolved subtype overlay space, and names the recovered runtime-state tail fields:
- `+0x40 = hold_token`
- `+0x41 = runtime_state_flag_41`
- `+0x42 = runtime_state_counter_42`
- `+0x44 = runtime_state_delta_44`
- `+0x46/+0x48 = owned_buffer_a`
- `+0x4a/+0x4c = owned_buffer_b`
- Those two runtime-state methods now carry provisional `EntityDispatchEntryRuntimeState * this` signatures and in-session comments tying them back to the older `000d:` evidence, which is enough to treat the runtime-state lane as class-authored rather than only documented.
## Questions To Close Later ## Questions To Close Later
- the remaining live `CRUSADER.EXE` method mapping for the note's old `0008:` / `000d:` anchors after the first `11e0:` base-method port and the `1440:` runtime-state port, especially `entity_word_list_destroy` and the timed/periodic constructors around old `0008:cefb` / `0008:d214`
- whether `+0x00` should be modeled as a literal `kind` field in all variants or only in some factory-built subtypes - whether `+0x00` should be modeled as a literal `kind` field in all variants or only in some factory-built subtypes
- exact ownership split between the base object and the embedded surfaces at `+0x1e` and `+0x28` - exact ownership split between the base object and the embedded surfaces at `+0x1e` and `+0x28`
- whether the seg126 startup/display subtype is truly part of the same inheritance family or only shares a lower-level dispatch-entry substrate - whether the seg126 startup/display subtype is truly part of the same inheritance family or only shares a lower-level dispatch-entry substrate

View file

@ -94,6 +94,7 @@ The live `CRUSADER.EXE` class-authoring lane is no longer just a plan.
Current authored `Remorse` classes in the active database are: Current authored `Remorse` classes in the active database are:
- `EntityDispatchEntry`
- `EntityVmOwnerResource` - `EntityVmOwnerResource`
- `EntityVmRuntime` - `EntityVmRuntime`
- `EntityVmContext` - `EntityVmContext`
@ -101,6 +102,10 @@ Current authored `Remorse` classes in the active database are:
The VM lane is still the furthest along in actual Ghidra authoring. Recent live batches added the bounded `EntityVmSlotEntry` class owner plus more owned `EntityVmRuntime` methods (`GetSlotChunkPtrAtOffset`, `ReleaseSlotChunkRef`, `TryUnloadSlotChunk`, `DebugDumpSlotMemory`, `ApplyToMatchingOwnerRows`) rather than stopping at free-function naming. The VM lane is still the furthest along in actual Ghidra authoring. Recent live batches added the bounded `EntityVmSlotEntry` class owner plus more owned `EntityVmRuntime` methods (`GetSlotChunkPtrAtOffset`, `ReleaseSlotChunkRef`, `TryUnloadSlotChunk`, `DebugDumpSlotMemory`, `ApplyToMatchingOwnerRows`) rather than stopping at free-function naming.
The next planned pilot family is no longer purely preparatory either. `Remorse::EntityDispatchEntry` now exists as a real class owner in-session with a first provisional `/Remorse/EntityDispatchEntryBase` datatype covering the stable field block through `+0x18` and a matching `/Remorse/EntityDispatchEntryVtable` datatype exposing only the verified `+0x14` and `+0x28` callback slots. The first base-method batch has also landed from the old `0008:` note cluster after re-anchoring that range onto the live `11e0:` process-substrate segment: `InitBase`, `SetSourceType`, `SetEventTypeChecked`, `SetGroupId`, `Unlink`, and `IncrementGroupId` now live under the class owner with provenance comments preserved.
That family also has its first derived slice now. The old `000d:7e00/8078` runtime-state pair is re-anchored in the live `1440:` fade/palette cluster as `InitRuntimeState` and `ReleaseRuntimeState`, and `/Remorse/EntityDispatchEntryRuntimeState` now exists as a provisional overlay datatype with the recovered `+0x40..+0x4c` runtime-state tail fields. That is a meaningful pause point because the pilot family now has a class owner, a base datatype, a vtable shell, a first base-method batch, and one concrete derived/runtime-state batch rather than just one isolated constructor lane.
The latest signature-recovery pass also tightened two of those runtime methods materially: The latest signature-recovery pass also tightened two of those runtime methods materially:
- `GetSlotChunkPtrAtOffset(runtime_farptr, slot_index, chunk_index, intra_chunk_offset)` now reads as a real slot-chunk accessor instead of a five-word anonymous wrapper. - `GetSlotChunkPtrAtOffset(runtime_farptr, slot_index, chunk_index, intra_chunk_offset)` now reads as a real slot-chunk accessor instead of a five-word anonymous wrapper.
@ -112,7 +117,11 @@ That VM-side gap is now closed too: `AcquireSlotForEntity` returns `EntityVmSlot
The next family switch has also landed in the live database: `Remorse::UsecodeDebuggerBreakState` now exists as a real class owner with a provisional `0x2f2` datatype and a stronger method batch (`Create`, `MaybeBreakOnCurrentLine`, `BreakpointInsertSorted`, `BreakpointRemove`, `HasBreakpoint`, `CallstackPushFrame`, `CallstackPushEntry`, `CallstackPopEntry`, `EnableSingleStep`, `ClearStepState`, `CurrentEntryGetUnitName`). The next family switch has also landed in the live database: `Remorse::UsecodeDebuggerBreakState` now exists as a real class owner with a provisional `0x2f2` datatype and a stronger method batch (`Create`, `MaybeBreakOnCurrentLine`, `BreakpointInsertSorted`, `BreakpointRemove`, `HasBreakpoint`, `CallstackPushFrame`, `CallstackPushEntry`, `CallstackPopEntry`, `EnableSingleStep`, `ClearStepState`, `CurrentEntryGetUnitName`).
That debugger family is no longer just a top-level shell. The internal record shapes are now recovered and applied live well enough to treat the two tables as real fixed-size arrays in-session: breakpoint entries are `0x0b` bytes with `unit_name_inline[9] + line_number`, and callstack entries are `0x15` bytes with `unit_name_inline[9]` plus the currently safest trailing fields `source_stream_target_farptr`, `current_frame_payload_farptr`, and still-neutral `aux_farptr`. That debugger family is no longer just a top-level shell. The internal record shapes are now recovered and applied live well enough to treat the two tables as real fixed-size arrays in-session: breakpoint entries are `0x0b` bytes with `unit_name_inline[9] + line_number`, and callstack entries are `0x15` bytes with `unit_name_inline[9]` plus the currently safest trailing fields `source_stream_cursor_farptr`, `current_frame_payload_farptr`, and still-neutral `aux_farptr`.
The next debugger pass tightened the bounded helper and callback edges too. `1408:0230` now lives under `Remorse::UsecodeDebuggerBreakState::BreakpointFindFirstForUnitAtOrAfterLine` instead of as an anonymous seg1408 helper, and the retail vtable root at `1478:65ab` is no longer a blind spot: slot 0 resolves to `OnBreakTriggeredNoop` and slot 1 resolves to `VtableSlot1ReturnZero`, which keeps the class surface honest about the shipped build's inert break callbacks while leaving non-retail behavior open.
The follow-up seg109 consumer pass is also done now. `13a0:0291` and its local helper `13a0:045c` are documented in-session as the first concrete consumers of the current callstack entry's trailing payload: they read entry `+0x09` as a descriptor/source-stream cursor and entry `+0x0d` as the current-frame payload context while formatting debugger dump/watch text. That cursor name is now promoted into the live `/Remorse/UsecodeDebuggerCallstackEntry` datatype and the `CallstackPushFrame` signature too, which means the remaining open callstack question is mostly the unused `aux_farptr` lane rather than the first two dwords.
The VM lane also advanced one more selective step without overpromoting inheritance: `Remorse::EntityVmContext::CreateFromSlotIndex` now has a caller-backed mixed parameter pack (`owner_source_farptr`, `pitemno_farptr`, `mode_flags`, `slot_index`, `value_add_offset`, `intra_chunk_offset`, `ucparam_farptr`, `ucparamsize`) and an explicit far return restored in `AX:DX`, even though the current live endpoint still textualizes that repaired signature conservatively as plain `dword __cdecl`. The VM lane also advanced one more selective step without overpromoting inheritance: `Remorse::EntityVmContext::CreateFromSlotIndex` now has a caller-backed mixed parameter pack (`owner_source_farptr`, `pitemno_farptr`, `mode_flags`, `slot_index`, `value_add_offset`, `intra_chunk_offset`, `ucparam_farptr`, `ucparamsize`) and an explicit far return restored in `AX:DX`, even though the current live endpoint still textualizes that repaired signature conservatively as plain `dword __cdecl`.

View file

@ -0,0 +1,146 @@
# `Using map patch file.` in retail `CRUSADER.EXE`
This note records the current evidence-backed read of the startup line:
`Using map patch file.`
Short version:
- the line is printed during `Init_Everything` startup
- it is gated by a file-existence check for `static\fixed.dat`
- it does **not** mean the `-u` usecode override is active
- it means the game found an alternate fixed-map archive and will prefer that archive for later fixed-map loading
- current recovered behavior looks like `replacement-preferred fixed-map source`, not `merge a few patched records into the base archive`
## Exact Startup Print Site
The live exported Ghidra C for `Init_Everything` at `1048:039b` shows this sequence:
1. `LoadConfigFile()`
2. `Init_CheckFreeDiskSpace()`
3. `File_Exists(s_static_fixed_dat)`
4. if present, `ConsolePrintf(..., 0x9cc, 0x78)`
5. print the generic loading/progress strings
The relevant string symbols in the live export are:
- `1478:09bb` = `s_static\fixed.dat`
- `1478:09cc` = `s_Using_map_patch_file.`
- `1478:09e4` = `s_Loading:_[`
- `1478:09ef` = `s__]`
- `1478:09fd` = `s_dot`
So the startup line is not speculative or inferred from neighboring strings. The init code really does:
- check whether `static\fixed.dat` exists
- and print `Using map patch file.` only when that file is present
## What The File Is
The nearby fixed-data loader path now closes this pretty tightly.
`ItemCacheFixedDat_Init()` is called later in startup from the same `Init_Everything` body. That wrapper immediately calls `ItemCache_InitAndLoadFixedDat()` at `10a8:163a`.
`ItemCache_InitAndLoadFixedDat()` does all of the following:
- initializes item data
- loads the normal base fixed-map archive through `FixedDat_LoadData()` at `10b8:0616`
- checks again for `static\fixed.dat`
- if present, loads that second archive into `DAT_1478_1064`
- resets `g_currentMapArray = 0xffff`
`FixedDat_LoadData()` itself resolves the standard asset path from `g_fixedDatFilenamePtr` and opens the regular `fixed.dat` resource.
That means the printed line is specifically about an alternate fixed-map archive, not a config file, not a save file, and not a usecode package.
## What It Does At Runtime
The strongest currently recovered consumer is the fixed-map load path in the same item-cache family.
In the exported Ghidra C, the map-load logic does this:
- if `DAT_1478_1064 == 0`, use `DAT_1478_1060` (the normal `fixed.dat` handle)
- otherwise use `DAT_1478_1064` (the `static\fixed.dat` handle)
That is stronger than a vague `patch support` claim. The current recovered shape is:
- base `fixed.dat` is always loaded
- `static\fixed.dat` is conditionally loaded when present
- later fixed-map reads prefer the `static\fixed.dat` handle when it exists
Current safest interpretation:
- the message means the game found an alternate fixed-map archive under `STATIC\FIXED.DAT`
- subsequent fixed-object/map loading will use that archive as the active source
## Merge Or Fallback Status
Current evidence does **not** show a merge path.
What is directly recovered:
- the game keeps two archive handles: base `DAT_1478_1060` and optional patch `DAT_1478_1064`
- the main fixed-map load path chooses exactly one handle before reading the map entry
- if `DAT_1478_1064` is non-null, that chooser uses it instead of `DAT_1478_1060`
- no currently recovered outer code does `try patch, then fall back to base if missing`
- no currently recovered outer code reads both archives and concatenates item lists
So the strongest current read is:
- `static\fixed.dat` is a replacement-preferred archive source
- not a recovered additive overlay system
That means the current evidence does **not** support claims like:
- `missing map entries in static\fixed.dat are automatically read from base fixed.dat`
- `items missing from the patch archive are filled from the base archive`
- `the patch archive appends extra records onto the base archive at load time`
Could there still be fallback hidden inside the archive object's internal methods? Possibly, but there is no evidence of that in the currently recovered call shape. The visible loader logic selects one archive handle up front and passes only that handle into the read methods.
Current safest practical conclusion:
- if `static\fixed.dat` is present, the game behaves like it is loading maps from that archive instead of the base archive
- using it to `add a few extra things to the base one` is not a recovered supported mode
- using it as a full replacement archive is the behavior the current code most clearly supports
## What It Probably Does Not Mean
Current evidence argues against a few common misreads.
It is **not** currently the `-u` startup override:
- the retail `-u` lane targets the EUSECODE runtime root, documented separately in `docs/usecode-startup-override.md`
- this startup print is in the fixed-map/archive lane instead
It is also **not** currently evidenced as a merge-style overlay:
- the recovered map-load chooser selects one handle or the other
- this consumer does not show `check patch archive first, then fall back per-record to base`
So the safest current wording is `replacement-preferred alternate FIXED.DAT source`, not `per-entry patch merge`.
## Practical Meaning
When retail No Remorse prints `Using map patch file.` at startup, it means:
- `STATIC\FIXED.DAT` was found
- the game has enabled its alternate fixed-map archive lane
- later fixed map/object loads will prefer that archive over the normal `FIXED.DAT`
In plain terms: the executable is telling you it found a replacement/patch copy of the world-map data archive and is going to load map content from that patched archive path.
## Evidence Summary
- `1048:039b Init_Everything` checks `File_Exists("static\\fixed.dat")` and prints `1478:09cc` only on success
- `10a8:163a ItemCache_InitAndLoadFixedDat` loads base `fixed.dat` plus optional `static\\fixed.dat`
- `10b8:0616 FixedDat_LoadData` resolves the standard `fixed.dat` path from `g_fixedDatFilenamePtr`
- recovered fixed-map load logic prefers `DAT_1478_1064` (`static\\fixed.dat`) over `DAT_1478_1060` (base `fixed.dat`) when the optional archive is present
## Ghidra Annotation Status
The live-session note to add in Ghidra is straightforward:
`Init_Everything startup status print: if static\\fixed.dat exists, print "Using map patch file.". Later ItemCache_InitAndLoadFixedDat loads that archive into DAT_1478_1064, and the fixed-map load path prefers DAT_1478_1064 over the base fixed.dat handle DAT_1478_1060.`
In this session the live comment could not be pushed automatically because the reachable MCP bridge endpoints for the open GUI session were unavailable and the local PyGhidra writer path is blocked by the project lock while Ghidra owns the project.

View file

@ -144,9 +144,9 @@ The live debugger-state model is now strong enough to split the old table blobs
| Offset | Current name | Confidence | Current meaning | | Offset | Current name | Confidence | Current meaning |
|---|---|---|---| |---|---|---|---|
| `+0x00..+0x08` | `unit_name_inline[9]` | High | Inline unit-name buffer for the active frame. | | `+0x00..+0x08` | `unit_name_inline[9]` | High | Inline unit-name buffer for the active frame. |
| `+0x09` | `source_stream_target_farptr` | Medium | Far pointer derived from the interpreter source-stream lane plus one fetched word in the only verified caller. | | `+0x09` | `source_stream_cursor_farptr` | High | Far pointer to the current debugger/source descriptor stream cursor. `Debugump_13a0_0291` passes this lane into `13a0:045c`, which reads descriptor bytes and inline strings directly from it. This field name is now promoted into the live datatype in `CRUSADER.EXE`, not just the note set. |
| `+0x0d` | `current_frame_payload_farptr` | Medium | Far pointer to the current frame payload at `frame_base + 0x04` in the only verified caller. | | `+0x0d` | `current_frame_payload_farptr` | High | Far pointer to the current frame payload/evaluation context at `frame_base + 0x04`. `13a0:045c` dereferences this lane while formatting debugger dump/watch text. |
| `+0x11` | `aux_farptr` | Low | Trailing auxiliary far pointer slot; still zero in the only verified caller. | | `+0x11` | `aux_farptr` | Low | Trailing auxiliary far pointer slot; still zero in the only verified `CallstackPushFrame` caller and still lacks a confirmed current-entry consumer. |
## Current Working Layout ## Current Working Layout
@ -176,6 +176,7 @@ Verified first live class batch landed on 2026-04-06.
- `1408:0053` -> `MaybeBreakOnCurrentLine` - `1408:0053` -> `MaybeBreakOnCurrentLine`
- `1408:00dd` -> `BreakpointInsertSorted` - `1408:00dd` -> `BreakpointInsertSorted`
- `1408:01a5` -> `BreakpointRemove` - `1408:01a5` -> `BreakpointRemove`
- `1408:0230` -> `BreakpointFindFirstForUnitAtOrAfterLine`
- `1408:029e` -> `HasBreakpoint` - `1408:029e` -> `HasBreakpoint`
- `1408:02f5` -> `CallstackPushFrame` - `1408:02f5` -> `CallstackPushFrame`
- `1408:03b0` -> `CallstackPushEntry` - `1408:03b0` -> `CallstackPushEntry`
@ -183,11 +184,14 @@ Verified first live class batch landed on 2026-04-06.
- `1408:0419` -> `EnableSingleStep` - `1408:0419` -> `EnableSingleStep`
- `1408:0432` -> `ClearStepState` - `1408:0432` -> `ClearStepState`
- `1408:0444` -> `CurrentEntryGetUnitName` - `1408:0444` -> `CurrentEntryGetUnitName`
- Promoted the remaining bounded breakpoint-table helper `1408:0230` under the class owner as `BreakpointFindFirstForUnitAtOrAfterLine`; it now reads as the lower-bound search over `breakpoint_entries` for a given `(unit_name, line_number)` query instead of an anonymous seg1408 utility.
- Resolved the retail debugger vtable root at `1478:65ab` one step further: slot 0 points to `1408:046f` and slot 1 points to `1408:0474`, and both entries are now class-owned as `OnBreakTriggeredNoop` and `VtableSlot1ReturnZero` with explicit comments that the shipped retail implementations are inert stubs.
- Tightened the live method signatures to explicit object-style forms, including: - Tightened the live method signatures to explicit object-style forms, including:
- `UsecodeDebuggerBreakState * __cdecl16far Create(UsecodeDebuggerBreakState * this, dword init_spec)` - `UsecodeDebuggerBreakState * __cdecl16far Create(UsecodeDebuggerBreakState * this, dword init_spec)`
- `void __cdecl16far MaybeBreakOnCurrentLine(UsecodeDebuggerBreakState * this, word current_line)` - `void __cdecl16far MaybeBreakOnCurrentLine(UsecodeDebuggerBreakState * this, word current_line)`
- `byte __cdecl16far BreakpointInsertSorted(UsecodeDebuggerBreakState * this, dword unit_name_farptr, word line_number)` - `byte __cdecl16far BreakpointInsertSorted(UsecodeDebuggerBreakState * this, dword unit_name_farptr, word line_number)`
- `void __cdecl16far BreakpointRemove(UsecodeDebuggerBreakState * this, dword unit_name_farptr, word line_number)` - `void __cdecl16far BreakpointRemove(UsecodeDebuggerBreakState * this, dword unit_name_farptr, word line_number)`
- `int __cdecl16far BreakpointFindFirstForUnitAtOrAfterLine(UsecodeDebuggerBreakState * this, dword unit_name_farptr, word line_number)`
- `uint __cdecl16far HasBreakpoint(UsecodeDebuggerBreakState * this, dword unit_name_farptr, word line_number)` - `uint __cdecl16far HasBreakpoint(UsecodeDebuggerBreakState * this, dword unit_name_farptr, word line_number)`
- `void __cdecl16far CallstackPushFrame(UsecodeDebuggerBreakState * this, dword unit_name_farptr, dword source_stream_target_farptr, dword current_frame_payload_farptr, dword aux_farptr)` - `void __cdecl16far CallstackPushFrame(UsecodeDebuggerBreakState * this, dword unit_name_farptr, dword source_stream_target_farptr, dword current_frame_payload_farptr, dword aux_farptr)`
- `byte __cdecl16far CallstackPushEntry(UsecodeDebuggerBreakState * this, dword unit_name_farptr)` - `byte __cdecl16far CallstackPushEntry(UsecodeDebuggerBreakState * this, dword unit_name_farptr)`
@ -195,6 +199,11 @@ Verified first live class batch landed on 2026-04-06.
- `void __cdecl16far EnableSingleStep(UsecodeDebuggerBreakState * this)` - `void __cdecl16far EnableSingleStep(UsecodeDebuggerBreakState * this)`
- `void __cdecl16far ClearStepState(UsecodeDebuggerBreakState * this)` - `void __cdecl16far ClearStepState(UsecodeDebuggerBreakState * this)`
- `dword __cdecl16far CurrentEntryGetUnitName(UsecodeDebuggerBreakState * this)` - `dword __cdecl16far CurrentEntryGetUnitName(UsecodeDebuggerBreakState * this)`
- The only verified `CallstackPushFrame` caller at `1418:051d` is now constrained a little more tightly in-session too: the trailing payload is still best kept as `source_stream_target_farptr`, `current_frame_payload_farptr`, and `aux_farptr`, but the raw stack setup now confirms that the last slot is literal zero in retail, the middle slot is pushed from `frame_base + 0x04`, and the first slot is pushed from the interpreter `+0xd6/+0xd8` source-stream lane plus a local offset.
- The next seg109 consumer pass closed the main follow-up from that batch. `13a0:0291 Debugump_13a0_0291` now has a decompiler comment showing that it resolves the current callstack entry as `this + 0x67 + depth * 0x15`, passes entry `+0x09` as the descriptor/source-stream cursor, and passes entry `+0x0d` as the frame payload context into `13a0:045c`.
- `13a0:045c FUN_13a0_045c` now also carries a decompiler comment recording the same split from the consumer side: it reads descriptor bytes and inline strings directly from the `+0x09` lane and dereferences the `+0x0d` lane as the evaluation context while formatting debugger dump/watch text into the shared output buffer at `0x45a6`.
- The `CallstackPushFrame` comment in seg1408 was updated to reflect that narrower live read: `+0x09` is no longer just a generic source-derived far pointer, but a real source-stream cursor used by the seg109 formatter path.
- That naming decision is now applied live too. `/Remorse/UsecodeDebuggerCallstackEntry` now exposes `source_stream_cursor_farptr` at offset `+0x09` with a matching field comment in the datatype manager, and `CallstackPushFrame` now uses `source_stream_cursor_farptr` in its parameter list instead of the older `source_stream_target_farptr` wording.
- Added decompiler comments on the breakpoint and callstack helpers so the recovered inline-record layout is visible in-session even before every field is formally typed. - Added decompiler comments on the breakpoint and callstack helpers so the recovered inline-record layout is visible in-session even before every field is formally typed.
- Added decompiler comments on the only verified `Interpreter_NextUsecodeOp` caller of `CallstackPushFrame`, which confirms the current live read of the three trailing callstack dwords: - Added decompiler comments on the only verified `Interpreter_NextUsecodeOp` caller of `CallstackPushFrame`, which confirms the current live read of the three trailing callstack dwords:
- `source_stream_target_farptr` is source-stream-derived from the interpreter `+0xd6/+0xd8` lane plus one fetched word - `source_stream_target_farptr` is source-stream-derived from the interpreter `+0xd6/+0xd8` lane plus one fetched word
@ -204,15 +213,16 @@ Verified first live class batch landed on 2026-04-06.
## Current Cautions ## Current Cautions
- The retail instantiation path still appears absent; no normal caller currently reaches `Create` in the unpatched retail binary. - The retail instantiation path still appears absent; no normal caller currently reaches `Create` in the unpatched retail binary.
- The record boundaries inside both tables are now landed in the live datatype, and two of the three trailing callstack dwords now have caller-backed structural names. The exact gameplay role behind those two far pointers is still only partly recovered. - The record boundaries inside both tables are now landed in the live datatype, and the first two trailing callstack dwords now have both producer-side and seg109 consumer-side structural evidence plus live datatype names/comments. The remaining uncertainty is no longer whether those lanes are meaningful, but whether they should ever become more subsystem-specific than `source_stream_cursor_farptr` and `current_frame_payload_farptr`.
- The retail vtable root is no longer an open slot-map question for the first two entries. What remains open is whether any non-retail or UI-side build ever installed non-stub behavior behind those same callback positions.
- `init_spec` on `Create` and `unit_name_farptr` on the breakpoint/callstack helpers are intentionally neutral names; the live signatures are object-correct, but the payload semantics should stay conservative. - `init_spec` on `Create` and `unit_name_farptr` on the breakpoint/callstack helpers are intentionally neutral names; the live signatures are object-correct, but the payload semantics should stay conservative.
## Best Next Moves ## Best Next Moves
1. Identify the real gameplay semantics of `source_stream_target_farptr` and `current_frame_payload_farptr` from the interpreter-side caller lanes before promoting subsystem-specific names. 1. Cross-check the seg1408 class note against the interpreter callback site at `1418:04b5` so the dormant-orphan lifecycle remains explicit in the live notes now that slot 0 is confirmed to land on an inert retail stub.
2. Identify the vtable callback slots used by `MaybeBreakOnCurrentLine` and decide whether one or two additional methods belong on the class owner. 2. Decide whether `aux_farptr` should remain neutral or can be promoted after one more caller or consumer pass.
3. Cross-check the seg1408 class note against the interpreter callback site at `1418:04b5` so the dormant-orphan lifecycle remains explicit in the live notes. 3. Decide whether `13a0:0291` and `13a0:045c` are ready for stable debugger-UI names or should remain comment-backed until another direct caller or string anchor lands.
4. Decide whether `aux_farptr` should remain neutral or can be promoted after one more caller or consumer pass. 4. If the debugger family stalls there, switch to the next planned class-lift family instead of overworking this orphaned subsystem.
## Bottom Line ## Bottom Line

View file

@ -9,6 +9,14 @@ Rules for keeping it useful:
## Remaining TODOs ## Remaining TODOs
### Apply-Class-Layout Schema Parity
- Missing capability: reliable minimal-payload use of `apply_class_layout(...)` during live class-lift batches.
- Current fallback: create the class namespace and provisional structs directly through live `run_write_script(...)`, then defer any later class-binding or per-method typing work.
- Why it matters: the first `EntityDispatchEntry` pilot batch reached the point where the class shell and provisional datatypes existed, but the endpoint still rejected the bind attempt with an undocumented required `methods` property even though the local workflow only needed `class_path`, `instance_struct`, and `vtable_struct`.
- Proposed MCP behavior: `apply_class_layout(...)` should accept a true minimal bind payload when no method list is being applied, or else the bridge/schema should expose the `methods` field explicitly and treat an omitted list as empty instead of a validation error.
- Latest status (2026-04-07): live `CRUSADER.EXE` class-lift pass for `Remorse::EntityDispatchEntry` succeeded via `run_write_script(...)`, creating the class shell plus `/Remorse/EntityDispatchEntryBase` and `/Remorse/EntityDispatchEntryVtable`. The only failed step in that batch was the direct `apply_class_layout(...)` call, which rejected the payload before any class work ran.
### Class-Lift Typing Live Parity ### Class-Lift Typing Live Parity
- Missing capability: end-to-end live-session parity for storage-aware `this` typing on 16-bit NE methods whose current storage does not match the default pointer storage the binder would choose. - Missing capability: end-to-end live-session parity for storage-aware `this` typing on 16-bit NE methods whose current storage does not match the default pointer storage the binder would choose.

View file

@ -15,6 +15,8 @@ Detailed completed analysis belongs in the files under `docs/`, not in this plan
## Progress Snapshot ## Progress Snapshot
Latest verified batch: [docs/startup-map-patch-file.md](docs/startup-map-patch-file.md) now closes the long-standing startup string `Using map patch file.` tightly enough to stop treating it as a vague debug/status artifact. Current best read is that `Init_Everything` prints that line only when `static\fixed.dat` exists, and the later fixed-map cache path then prefers the loaded `static\fixed.dat` archive handle over the base `fixed.dat` handle for map/fixed-object reads. The remaining uncertainty in this lane is now narrow: whether any later consumer does a finer-grained fallback/merge than the first recovered chooser, not what the startup line is referring to in the first place.
Latest verified batch: [docs/psx/psx.md](docs/psx/psx.md), [docs/psx/map-rendering.md](docs/psx/map-rendering.md), [docs/psx/map-viewer-plan.md](docs/psx/map-viewer-plan.md), and [docs/psx/art-binding-recovery.md](docs/psx/art-binding-recovery.md) now tighten the PSX render-side model another step in both Ghidra and the viewer exporter. The earlier `DAT_800758d4` consumer finding remains intact and is still wired into the viewer-side cache path as explicit `companionExtents` metadata, but the bigger practical change in this batch is the first measured art-binding recovery pass for the viewer exporter: the PSX cache builder now treats large zero-block `DAT_800758d8` constructor-placement bands as inherited-art candidates, first via same-map `DAT_800758cc` script-signature donors and then via a constrained nearest-donor fallback inside the current `0x003e..0x0064` family. That rebuild moved the scene set from `58,262` fallback items / `1,714` bundle-mapped items to `25,038` fallback items / `34,938` bundle-mapped items, making early representative maps such as `0`, `9`, and `43` mostly real-art while leaving `map 104` and the remaining `0x0042` / `0x0055..0x0063` constructor-placement band as the clearest unresolved outliers. The practical remaining gap is therefore narrower now: not "why are most PSX scenes placeholders" but "what executable-backed alias/resource rule explains the remaining zero-block constructor-placement families without leaning on donor heuristics." Latest verified batch: [docs/psx/psx.md](docs/psx/psx.md), [docs/psx/map-rendering.md](docs/psx/map-rendering.md), [docs/psx/map-viewer-plan.md](docs/psx/map-viewer-plan.md), and [docs/psx/art-binding-recovery.md](docs/psx/art-binding-recovery.md) now tighten the PSX render-side model another step in both Ghidra and the viewer exporter. The earlier `DAT_800758d4` consumer finding remains intact and is still wired into the viewer-side cache path as explicit `companionExtents` metadata, but the bigger practical change in this batch is the first measured art-binding recovery pass for the viewer exporter: the PSX cache builder now treats large zero-block `DAT_800758d8` constructor-placement bands as inherited-art candidates, first via same-map `DAT_800758cc` script-signature donors and then via a constrained nearest-donor fallback inside the current `0x003e..0x0064` family. That rebuild moved the scene set from `58,262` fallback items / `1,714` bundle-mapped items to `25,038` fallback items / `34,938` bundle-mapped items, making early representative maps such as `0`, `9`, and `43` mostly real-art while leaving `map 104` and the remaining `0x0042` / `0x0055..0x0063` constructor-placement band as the clearest unresolved outliers. The practical remaining gap is therefore narrower now: not "why are most PSX scenes placeholders" but "what executable-backed alias/resource rule explains the remaining zero-block constructor-placement families without leaning on donor heuristics."
- Overall useful decompilation progress: about 58% - Overall useful decompilation progress: about 58%
@ -80,6 +82,12 @@ Latest verified batch: [docs/psx/psx.md](docs/psx/psx.md), [docs/psx/map-renderi
- The next family switch also landed: `Remorse::UsecodeDebuggerBreakState` now exists as a real class owner with a `0x2f2` provisional datatype plus a first method batch for construction, breakpoint gating, breakpoint table helpers, callstack helpers, and step-state helpers. - The next family switch also landed: `Remorse::UsecodeDebuggerBreakState` now exists as a real class owner with a `0x2f2` provisional datatype plus a first method batch for construction, breakpoint gating, breakpoint table helpers, callstack helpers, and step-state helpers.
- That debugger batch is already tighter than the initial shell: `1408:01a5` is now verified as `BreakpointRemove`, `1408:02f5` is now verified as `CallstackPushFrame`, breakpoint entries are recovered as `0x0b` inline-name-plus-line records, and callstack entries are recovered as `0x15` inline-name-plus-three-dword records even though the trailing dword semantics remain open. - That debugger batch is already tighter than the initial shell: `1408:01a5` is now verified as `BreakpointRemove`, `1408:02f5` is now verified as `CallstackPushFrame`, breakpoint entries are recovered as `0x0b` inline-name-plus-line records, and callstack entries are recovered as `0x15` inline-name-plus-three-dword records even though the trailing dword semantics remain open.
- The next pass landed the debugger struct rewrite in-session too: `/Remorse/UsecodeDebuggerBreakpointEntry`, `/Remorse/UsecodeDebuggerCallstackEntry`, and the updated `/Remorse/UsecodeDebuggerBreakState` array layout now exist live instead of only in notes, and the only verified `CallstackPushFrame` caller now narrows those three trailing dwords to `source_stream_target_farptr`, `current_frame_payload_farptr`, and still-neutral `aux_farptr`. - The next pass landed the debugger struct rewrite in-session too: `/Remorse/UsecodeDebuggerBreakpointEntry`, `/Remorse/UsecodeDebuggerCallstackEntry`, and the updated `/Remorse/UsecodeDebuggerBreakState` array layout now exist live instead of only in notes, and the only verified `CallstackPushFrame` caller now narrows those three trailing dwords to `source_stream_target_farptr`, `current_frame_payload_farptr`, and still-neutral `aux_farptr`.
- The latest debugger class-lift pass closed two more bounded gaps without overpromoting semantics: `1408:0230` now lives under `Remorse::UsecodeDebuggerBreakState::BreakpointFindFirstForUnitAtOrAfterLine` as the breakpoint-table lower-bound helper for `(unit_name, line_number)` queries, and the retail vtable root at `1478:65ab` is now resolved enough to show that `MaybeBreakOnCurrentLine` dispatches slot 0 into a shipped no-op stub while slot 1 currently returns zero through a second inert method.
- The next debugger follow-up also closed the planned seg109 consumer pass: `13a0:0291` plus its helper `13a0:045c` now show that the current callstack entry's `+0x09` lane is a real source-stream cursor consumed byte-by-byte by the debugger formatter and that `+0x0d` is the paired current-frame payload context used for expression/watch rendering. The remaining open tail-field question is now mostly `aux_farptr`, not the first two dwords.
- That naming decision is now landed live rather than only in notes: `/Remorse/UsecodeDebuggerCallstackEntry` now names offset `+0x09` as `source_stream_cursor_farptr` with an in-session field comment, and `CallstackPushFrame` now carries the same parameter name in its signature. The debugger-family residue is therefore narrower again: mainly `aux_farptr`, plus whether the seg109 formatter helpers deserve stable names.
- The next planned pilot family also started for real: `Remorse::EntityDispatchEntry` now exists in-session with provisional `/Remorse/EntityDispatchEntryBase` and `/Remorse/EntityDispatchEntryVtable` datatypes, so this family is no longer just a note cluster. The remaining blocker is now concrete rather than vague: the current source note still points at older `0008:` / `000d:` anchors that are not yet ported back onto the live `CRUSADER.EXE` method objects, so the first base-method ownership move has to wait on that mapping step instead of being guessed.
- That mapping step is now partially closed too. The older `0008:ba00` base cluster ports into live `11e0:` by offset, and the first base-method batch now lives under `Remorse::EntityDispatchEntry`: `InitBase`, `SetSourceType`, `SetEventTypeChecked`, `SetGroupId`, `Unlink`, and `IncrementGroupId`. The next blocker on this family is therefore narrower again: not whether the pilot can move methods at all, but which live segments carry the remaining word-list, timed/periodic, and runtime-state methods from the older `0008:` / `000d:` notes.
- The runtime-state follow-up is now partially closed too. `FadeProcess_Create` is explicitly tagged by the decompiler as old `000d:7e00`, `FUN_1440_0278` matches the old `000d:8078` release path by both offset delta and behavior, and both now live under `Remorse::EntityDispatchEntry` as `InitRuntimeState` and `ReleaseRuntimeState` with a new `/Remorse/EntityDispatchEntryRuntimeState` overlay datatype. That leaves the remaining `EntityDispatchEntry` pilot work in a narrower end-of-day state: mainly the word-list destroy lane and the timed/periodic constructor cluster, not the core base or runtime-state surfaces.
- `CreateFromSlotIndex` is no longer a raw anonymous pack either: the live signature now separates `owner_source_farptr`, `pitemno_farptr`, `mode_flags`, `slot_index`, `value_add_offset`, `intra_chunk_offset`, `ucparam_farptr`, and `ucparamsize`, with explicit `AX:DX` return storage restored even though the endpoint still textualizes the function conservatively as plain `dword __cdecl`. - `CreateFromSlotIndex` is no longer a raw anonymous pack either: the live signature now separates `owner_source_farptr`, `pitemno_farptr`, `mode_flags`, `slot_index`, `value_add_offset`, `intra_chunk_offset`, `ucparam_farptr`, and `ucparamsize`, with explicit `AX:DX` return storage restored even though the endpoint still textualizes the function conservatively as plain `dword __cdecl`.
### Areas That Are No Longer Live Priorities ### Areas That Are No Longer Live Priorities
@ -116,7 +124,7 @@ Latest verified batch: [docs/psx/psx.md](docs/psx/psx.md), [docs/psx/map-renderi
5. Tighten the seg006 masked-helper caller chains so the local state-selector/value family can be tied to concrete gameplay subsystems. 5. Tighten the seg006 masked-helper caller chains so the local state-selector/value family can be tied to concrete gameplay subsystems.
6. Classify the paired seg070 loops behind `entity_vm_runtime_owner_resource_create`, especially which temporary buffers and record schemas each family populates. 6. Classify the paired seg070 loops behind `entity_vm_runtime_owner_resource_create`, especially which temporary buffers and record schemas each family populates.
7. Stay on the Remorse VM class-lift batch while the repaired runtime lane is warm: use the now-recovered `CreateFromSlotIndex` caller pack to decide whether any remaining scalar positions deserve stronger typedefs, but keep the return semantically conservative until the base-process inheritance model is explicit enough to justify a prettier live return type. 7. Stay on the Remorse VM class-lift batch while the repaired runtime lane is warm: use the now-recovered `CreateFromSlotIndex` caller pack to decide whether any remaining scalar positions deserve stronger typedefs, but keep the return semantically conservative until the base-process inheritance model is explicit enough to justify a prettier live return type.
8. Continue the `UsecodeDebuggerBreakState` family from the now-landed live array layout: identify the exact gameplay semantics of `source_stream_target_farptr` and `current_frame_payload_farptr`, then decide whether `aux_farptr` should remain neutral and whether any further seg1408 or interpreter-side helpers belong under that class before widening into another family. 8. Continue the `UsecodeDebuggerBreakState` family from the now-landed live array layout, callback-map pass, seg109 consumer pass, and live datatype promotion only if the last `aux_farptr` lane can be closed cheaply; otherwise resume from the current `EntityDispatchEntry` stopping point and map the remaining old `0008:` method groups onto live `CRUSADER.EXE` segments, especially the word-list destroy lane and the timed/periodic constructor cluster.
8. In the local GhidraMCP upgrade lane, add support for dual POST body decoding (`application/json` plus form-urlencoded) and a constrained live write-side PyGhidra endpoint family so future custom-storage/type repairs can stay inside the active MCP session when Python is enabled. 8. In the local GhidraMCP upgrade lane, add support for dual POST body decoding (`application/json` plus form-urlencoded) and a constrained live write-side PyGhidra endpoint family so future custom-storage/type repairs can stay inside the active MCP session when Python is enabled.
9. Promote additional ledger rows directly from already-verified docs and live comments, especially where segments already deserve `Foothold`, `Partial`, or `Deep`; the new seg029 step-aware sweep batch, seg031 queue-release batch, and seg090 movement-helper batch should be the immediate template. 9. Promote additional ledger rows directly from already-verified docs and live comments, especially where segments already deserve `Foothold`, `Partial`, or `Deep`; the new seg029 step-aware sweep batch, seg031 queue-release batch, and seg090 movement-helper batch should be the immediate template.
10. If the VM lane stalls, revisit `000e:ffb0` from the now-better-constrained video/audio caller windows and try to recover an adjacent non-overlapped helper before attempting broad boundary repair. 10. If the VM lane stalls, revisit `000e:ffb0` from the now-better-constrained video/audio caller windows and try to recover an adjacent non-overlapped helper before attempting broad boundary repair.