function userscript() -- https://stackoverflow.com/a/32389020 BITOR, BITXOR, BITAND = 1, 3, 4 function bitoper(a, b, oper) local r, m, s = 0, 2^31 repeat s,a,b = a+b+m, a%m, b%m r,m = r + m*oper%(s-a-b), m/2 until m < 1 return r end --[[ ============================ Alternate MLL Address Syntax ============================ --]] -- Alt ReadInteger function GetInt(address) local addressPointer = ffi.cast("int *", address) return addressPointer[0] end -- Alt WriteInteger function SetInt(address, value) local addressPointer = ffi.cast("int *", address) addressPointer[0] = value end -- Alt ReadByte function GetByte(address) local addressPointer = ffi.cast("char *", address) return addressPointer[0] end -- Alt WriteByte function SetByte(address, value) local addressPointer = ffi.cast("char *", address) addressPointer[0] = value end -- Alt ReadFloat function GetFloat(address) local addressPointer = ffi.cast("float *", address) return addressPointer[0] end -- Alt WriteFloat function SetFloat(address, value) local addressPointer = ffi.cast("float *", address) addressPointer[0] = value end -- Var(0) passover PermVarAddress = GetInt(player.current():getplayeraddress() + 0xF1C) -- Offset Perm(500000) >> Anim Data Range -- 0x10 size PermVar_AnimList = PermVarAddress + 4*500000 -- X+0x00 = AnimID (Index is inferred by multiplication) -- X+0x04 = FirstHitbox (-1 def) -- X+0x08 = FirstHurtbox (-1 def) -- x+0x0C = LastHitbox (For slow motion debugging) -- Offset Perm(600000) >> State Data Range PermVar_StateList = PermVarAddress + 4*600000 -- X+0 = StateID -- X+4 = AnimHeader via AnimIndex -> AnimID (With AnimList) HITDEF_DATA = { } -- Perm(100000) - Pointer for Hitdef Data -- Perm(100001) - Hitdef Data Count (Size 0x??) -- Syntax >>> GetHitdef(1) -- Dump Var(0), Var(1), Var(2), Var(3) -- HITDEF == -- 0x00 Statedef Number -- 0x04 Flags -- 1 IgnoreHitPause = 1 -- 2 IgnoreHitPause = 0 -- 3 = Both -- 4 = Reversible -- 8 = Irreversable -- 12 = Both -- 0x08 Statedef Anim Header >> First Element Hitbox (Reverse Lookup from Anim Object Table) HELPER_DATA = { } CT_HELPER_FLAG = -1 -- Perm(100002) - Pointer for all Helper Controller Data -- Perm(100003) - Helper Data Count (Size 0x08 -> 0x0C) -- HELPER == -- 0x00 Statedef Number -- 0x04 Helper Status (1 = Normal Only, 2 = Player Only, 3 = Both) --[[ ===================== ANIMATION DATA START ===================== Note I am mostly reversing this from the anim.lua documentation and AI_Assist's Analyze file It's better to understand how the pointer structure works than to use lua functions.. --]] mugen.log("\n\n" .. "BEGINNING ANIMATION ANALYSIS" .. "\n") AnimData = GetInt(GetInt(GetInt(player.current():enemy():getplayeraddress() + 0x1534))) AnimCount = GetInt(AnimData + 0x08) mugen.log("Animation Count: " .. AnimCount .. "\n") AnimDataList = GetInt(AnimData + 0x18) AnimInfoList = GetInt(AnimData + 0x1C) -- Debug mugen.log(string.format("AnimDataList 0x%08x.\n", tonumber(AnimDataList))) mugen.log(string.format("AnimInfoList 0x%08x.\n", tonumber(AnimInfoList))) -- AnimDataList 0x14 Each Anim -- 0x00 DataAddress (Pointer) -- 0x08 >> Element Count -- 0x18 >> Element Data List (Pointer) (EACH ELEMENT 0x8C) -- 0x04 Length (?) -- 0x84 CLSN1 Data (Pointer, 0 if no CLSN1) -- 0x88 CLSN2 Data (Pointer, 0 if no CLSN2) -- COLLISION DATA (Both share same structure) -- 0x00 ? -- 0x04 CLSN_TYPE_COUNT -- 0x08 BOUNDING_DEFINITION_POINTER (EACH 0x14) -- 0x00 ? -- 0x04 Left -- 0x08 Top -- 0x0C Right -- 0x10 Bottom -- 0x04 ? -- 0x08 Anim Length (Element Count) -- 0x0C Frame? -- 0x10 HasLoop -- Samples -- [[26a75f40]+0x18]+88 -- [[[26a75f40]+0x18]+88] -- [[[[26a75f40]+0x18]+88]+0x08] -- AnimInfoList 0x10 Each Anim -- 0x00 DataAddress (Pointer) -- 0x04 Anim Index (0 Indexed) -- 0x08 ? -- 0x0C AnimID (Animation Number) -- Lookup Objects (I don't think a double lookup is necessary but easier for me to code so..) -- 0 Indexing or not? -- ID >> Index AnimID_TOINDEX = { } -- Index >> ID AnimIndex_TOID = { } StateID_TOINDEX = { } StateIndex_TOID = { } Hitbox = -1 Hurtbox = -1 CurrentAnimIndex = 0 for i = AnimCount,1,-1 do ThisDataList = AnimDataList + (CurrentAnimIndex * 0x14) ThisInfoList = AnimInfoList + (CurrentAnimIndex * 0x10) -- AnimIndex 0x04 ThisAnimIndex = GetInt(ThisInfoList + 0x04) -- AnimID 0x0C ThisAnimID = GetInt(ThisInfoList + 0x0C) -- mugen.log("Testing: " .. CurrentAnimIndex .. " And " .. ThisAnimID .. "\n") AnimIndex_TOID[ThisAnimIndex] = ThisAnimID AnimID_TOINDEX[ThisAnimID] = ThisAnimIndex -- Current Animation Data ThisAnimData = GetInt(ThisDataList) -- Animation Element Count AnimElemCount = GetInt(ThisAnimData + 0x08) -- Debug -- mugen.log("Index: " .. ThisAnimIndex .. " AnimID: " .. ThisAnimID .. " Count:" .. AnimElemCount .. "\n") -- Element Data List ElemDataList = GetInt(ThisAnimData + 0x18) -- Each Element 0x8C (Use with AnimElemCount) CurrentElemCount = 0 FirstHurtbox = -1 FirstHitbox = -1 LastHitbox = -1 DebugToggle = 0 for j = AnimElemCount,1,-1 do ElemCLSN1 = GetInt(ElemDataList + 0x84 + (CurrentElemCount * 0x8C)) ElemCLSN2 = GetInt(ElemDataList + 0x88 + (CurrentElemCount * 0x8C)) if (ElemCLSN1 ~= 0) then LastHitbox = CurrentElemCount + 1 DebugToggle = 1 if (FirstHitbox == -1) then FirstHitbox = CurrentElemCount + 1 end -- mugen.log("Hitbox " .. FirstHitbox .. " ") end if (ElemCLSN2 ~= 0 and FirstHurtbox == -1) then DebugToggle = 1 FirstHurtbox = CurrentElemCount + 1 -- mugen.log("Hurtbox " .. FirstHurtbox .. " ") end -- Inc CurrentElemCount = CurrentElemCount + 1 end SetInt(PermVar_AnimList, ThisAnimID) SetInt(PermVar_AnimList + 4, FirstHitbox) SetInt(PermVar_AnimList + 8, FirstHurtbox) SetInt(PermVar_AnimList + 12, LastHitbox) PermVar_AnimList = PermVar_AnimList + 16 -- Increment CurrentAnimIndex = CurrentAnimIndex + 1 end --[[ ================== ANIMATION DATA END ================== --]] -- Start of Data PV_DataOffset = PermVarAddress + (100000*4) -- Pointers for storage PointerArray = { ChangeState_CONST = PermVarAddress + 100*4, ChangeState_EXPR = PermVarAddress + 101*4 } CONTYPE_ChangeState = 01 CONTYPE_SelfState = 02 ChangeState_CONST = {} ChangeState_CONST_CT = 0 ChangeState_EXPR = {} ChangeState_EXPR_CT = 0 CONTYPE_VarSet = 04 CONTYPE_VarAdd = 05 CONTYPE_VarRandom = 06 CONTYPE_VarRangeSet = 07 CONTYPE_LifeSet = 10 CONTYPE_LifeAdd = 11 CONTYPE_HitBy = 30 CONTYPE_ChangeAnim = 32 CONTYPE_HitDef = 37 CONTYPE_ReversalDef = 38 CONTYPE_Projectile = 39 CONTYPE_HitFallDamage = 102 CONTYPE_HitOverRide = 120 CONTYPE_AssertSpecial = 150 CONTYPE_Pause = 212 CONTYPE_SuperPause = 214 CONTYPE_Helper = 300 CONTYPE_ParentVarSet = 304 CONTYPE_ParentVarAdd = 305 --[[ ============== STATEDEF ANALYSIS START ============== --]] Enemy_Cache = player.current():enemy():getinfoaddress() Enemy_StatePTR = GetInt(Enemy_Cache + 0x42C) Enemy_StateData = GetInt(Enemy_StatePTR) Enemy_StateDefCount = GetInt(Enemy_StateData + 0x08) Enemy_StateDefInfo = GetInt(Enemy_StateData + 0x18) Enemy_StateDefList = GetInt(Enemy_StateData + 0x1C) -- Resetting for Accessing indexes. PermVar_AnimList = PermVarAddress + 4*500000 --[[ -------------------- definfo -------------------- [definfo]+0x9C*n: each def --]] -- A special exception is made for overflow states, regardless of what other types they contain -- These are always in their own area only. CurrentStateDefCount = 0 while (CurrentStateDefCount < Enemy_StateDefCount) do -- List Data CurrStateDefList = Enemy_StateDefList + (CurrentStateDefCount * 0x10) CurrStateDefID = GetInt( CurrStateDefList + 0x08) -- Print Statedef Number mugen.log("STATEDEF " .. CurrStateDefID .. "\n") -- Statedef Anim Header Statedef_Anim_Header = Enemy_StateDefInfo + (CurrentStateDefCount * 0x9C) + 0x80 -- 0x00 == Constant Value (When 0x08 -1) -- 0x08 == -1 equals CONSTANT VALUE if (GetInt(Statedef_Anim_Header + 0x08) == -1) then Statedef_Anim_Header = GetInt(Statedef_Anim_Header) else Statedef_Anim_Header = -1 end -- Print Header Value -- mugen.log("Header: " .. Statedef_Anim_Header .. "\n") --[[ ================================ Getting Statedef MoveType Header ================================ --]] MoveType_Address = Enemy_StateDefInfo + (CurrentStateDefCount * 0x9C) + 0x08 MoveType_Header = GetInt(MoveType_Address) --[[ =================================================== Getting Hitbox Data from earlier animation analysis =================================================== --]] if (Statedef_Anim_Header ~= -1) then if (AnimID_TOINDEX[Statedef_Anim_Header] ~= nil) then TempIndex = AnimID_TOINDEX[Statedef_Anim_Header] Hitbox = GetInt(PermVar_AnimList + (TempIndex * 16) + 0x04) Hurtbox = GetInt(PermVar_AnimList + (TempIndex * 16) + 0x08) else -- Debug/Weird Code Hitbox = -1 Hurtbox = -1 -- mugen.log("Test: " .. Relative_FirstHitbox .. " AND " .. Relative_FirstHurtbox .. "\n") end else Hitbox = -1 Hurtbox = -1 end -- Relation Debugging -- StateIndex_TOID[CurrentStateDefCount] = ThisAnimID -- StateID_TOINDEX[CurrStateDefID] = CurrentStateDefCount --[[ =================== Controller analysis =================== --]] -- State Controller Analysis. SCP = GetInt( Enemy_StateDefInfo + (CurrentStateDefCount * 0x9C) ) SCP_COUNT = GetInt(SCP + 0x14) SCP_INFO = GetInt(SCP + 0x18) SCP_LIST = GetInt(SCP + 0x1C) -- Overflow Special if (SCP_COUNT >= 512) then NULLOVERFLOW = 1 end --[[ ======================== Controller analysis loop ======================== --]] CurrentStateCount = 0 while (CurrentStateCount < SCP_COUNT) do CurrentList = SCP_LIST + (0x10 * CurrentStateCount) CurrentInfo = SCP_INFO + (0x68 * CurrentStateCount) --[[ ==================== Controller Info Data ==================== --]] -- Controller Type CurrentController = GetInt(CurrentList + 0x08) -- IgnoreHitPause ConIHP = GetInt(CurrentInfo + 0x0C) -- 0x60 Extended Properties Pointer (OK if 0) ConProp = GetInt(CurrentInfo + 0x60) -- Apparently LUA Tables aren't 0 indexed.. how 'unique' -- Param Array ConParam = { GetInt(CurrentInfo + 0x18), GetInt(CurrentInfo + 0x24), GetInt(CurrentInfo + 0x30), GetInt(CurrentInfo + 0x3C), GetInt(CurrentInfo + 0x48), GetInt(CurrentInfo + 0x54) } -- Param is Const Array ConParamConst = { GetInt(CurrentInfo + 0x20), GetInt(CurrentInfo + 0x2C), GetInt(CurrentInfo + 0x38), GetInt(CurrentInfo + 0x44), GetInt(CurrentInfo + 0x50), GetInt(CurrentInfo + 0x5C) } TempTable = {}; --[[ ===================== ChangeState/SelfState ===================== 0x18/0x1C/0x20 = VALUE (STATE) 0x24/0x28/0x2C = CTRL (Default -1) 0x30/0x34/0x38 = ANIM (Default -1) --]] if (CurrStateDefID == 12345) then -- Debug mugen.log(string.format("CurrList 0x%08x.\n", tonumber(CurrentList))) mugen.log(string.format("CurrInfo 0x%08x.\n", tonumber(CurrentInfo))) mugen.log(" Type = " .. CurrentController .. "\n") mugen.log("Debug Const1 = " .. ConParamConst[1] .. "\n") mugen.log("Debug Val1 = " .. ConParam[1] .. "\n") mugen.log("Debug Const2 = " .. ConParamConst[2] .. "\n") mugen.log("Debug Val2 = " .. ConParam[2] .. "\n") mugen.log("Debug Const3 = " .. ConParamConst[3] .. "\n") mugen.log("Debug Val3 = " .. ConParam[3] .. "\n") end if (CurrentController == CONTYPE_ChangeState or CurrentController == CONTYPE_SelfState) then if (ConParamConst[1] == -1) then ChangeState_CONST[ChangeState_CONST_CT] = { StateDef = CurrStateDefID, IHP = ConIHP, Value = ConParam[1] } ChangeState_CONST_CT = ChangeState_CONST_CT + 1 else ChangeState_EXPR[ChangeState_EXPR_CT] = { StateDef = CurrStateDefID, IHP = ConIHP, Value = -1 } ChangeState_EXPR_CT = ChangeState_EXPR_CT + 1 end end --[[ ================ Loop Controllers ================ --]] CurrentStateCount = CurrentStateCount + 1 --[[ ========================= End State Controller Loop ========================= --]] end --[[ if (CT_HITDEF_FLAG ~= 0) then mugen.log("Data_Key_Tests >>> " .. CurrStateDefID .. " and " .. CT_HITDEF_FLAG .. " and " .. Hitbox .. "\n") table.insert(HITDEF_DATA, CurrStateDefID) table.insert(HITDEF_DATA, CT_HITDEF_FLAG) table.insert(HITDEF_DATA, Hitbox) end --]] --[[ ============== Loop Statedefs ============== --]] CurrentStateDefCount = CurrentStateDefCount + 1 end --[[ ==================== Object Data Writing ==================== --]] mugen.log("Begin Object Data Write Test\n") mugen.log(string.format("RegionTest 0x%08x.\n", PV_DataOffset)) -- Cumulative Stopgap Test LastStateDef = -4 -- Perm(100000) == 0x61A80 --[[ ================================= ChangeState/SelfState CONST Table ================================= --]] -- 0x00 Statedef -- 0x04 IgnoreHitPause -- 0x08 StateNo Const -- ChangeState/SelfState CONST Table SetInt(PointerArray['ChangeState_CONST'], PV_DataOffset) index = 0 TableLength = #ChangeState_CONST mugen.log("Test length: " .. TableLength .. "\n") while (index < TableLength) do SetInt(PV_DataOffset, ChangeState_CONST[index].StateDef) SetInt(PV_DataOffset + 4, ChangeState_CONST[index].IHP) SetInt(PV_DataOffset + 8, ChangeState_CONST[index].Value) PV_DataOffset = PV_DataOffset + 12 index = index + 1 end --[[ ====================================== ChangeState/SelfState Expression Table ====================================== --]] -- 0x00 Statedef -- 0x04 IgnoreHitPause -- 0x08 -1 mugen.log(string.format("RegionTest2 0x%08x.\n", PV_DataOffset)) -- ChangeState/SelfState CONST Table SetInt(PointerArray['ChangeState_EXPR'], PV_DataOffset) TableLength = #ChangeState_EXPR mugen.log("Test lengthExpr: " .. TableLength .. "\n") index = 0 while (index < TableLength) do SetInt(PV_DataOffset, ChangeState_EXPR[index].StateDef) SetInt(PV_DataOffset + 4, ChangeState_EXPR[index].IHP) SetInt(PV_DataOffset + 8, -1) PV_DataOffset = PV_DataOffset + 12 index = index + 1 end --[[ ============ ANALYSIS END ============ --]] end local status, err = pcall(userscript) if not status then mugen.log("Failed to run user script: " .. err .. "\n") end