-------------------------------------------------------------------------------------- -- New Super Mario Bros. DS Profile Lua Script -------------------------------------------------------------------------------------- -- This script reads active frame data from all frame-executed processes, then outputs -- the info NUM_FRAMES_OBJ frames behind the actual read. NUM_FRAMES_OBJ is set to 3 -- to match the info with the Nintendo DS displays. Only frame-executed processes are -- used/shown, thus if a frame-drawn process that has a sensor has not been frame- -- executed then it won't be visible (but the game will draw the process, if the game -- allows processes to be drawn without executed in the first place). -- -- NUM_OBJ_ENTRIES is set to a high number to output as many processes as possible. -- The lower NUM_OBJ_ENTRIES is, the faster the script will run. -- -- The info that is read is taken from the execution list, as the order of execution -- is key to synchronize a frame. -- The order of execution should usually be: -- PLAYER->ENEMY->PLATFORM/SOLID->CAMERA->LASTACTOR_STAGE(HITBOXes) -- -- By Powerline and Treeki -------------------------------------------------------------------------------------- --------------- -- Constants -- --------------- NUM_FRAMES_OBJ = 3 -- Number of frames to wait until the info will be drawn on screen. Default = 3. NUM_OBJ_ENTRIES = 96 -- Number of visible info on screen. The lower the faster. Default = 96. TOP_SCREEN_Y = -192 -- Offset of top screen to use when main screen is top screen. BOTTOM_SCREEN_Y = 0 -- Offset to bottom screen to use when main screen is bottom screen. SHOW_HITBOX = 1 -- Set to 1 to show hitboxes. SHOW_PLATFORM = 1 -- Set to 1 to show platforms. SHOW_SOLID = 1 -- Set to 1 to show solids. SHOW_SENSOR = 1 -- Set to 1 to show sensors. -- What color to draw info with: COLOR_HITBOX_IN = "#FF000080" COLOR_HITBOX_OUT = "#FF0000FF" COLOR_PLATFORM = "#00FF00FF" COLOR_SOLID_IN = "#0000FF80" COLOR_SOLID_OUT = "#0000FFFF" COLOR_SENSOR_BELOW = "#6DF6FFFF" COLOR_SENSOR_ABOVE = "#66FD86FF" COLOR_SENSOR_LEFT = "#FFFF60FF" COLOR_SENSOR_RIGHT = "#FFFF60FF" -------------------------------------------------------------------------------------- -- GetActiveLCDY() -------------------------------------------------------------------------------------- -- Reads POWERCNT register to find which screen is the main screen. -- -- By Powerline -------------------------------------------------------------------------------------- function GetActiveLCDY() if bit.band(0x8000, memory.readword(0x4000304)) > 0 then return TOP_SCREEN_Y end return BOTTOM_SCREEN_Y end -------------------------------------------------------------------------------------- -- GetNextConnectHierarchyPtr() -------------------------------------------------------------------------------------- -- Get the next connect hierarchy pointer in the hierarchy list. First travels the -- children, and then its siblings. -- -- Takes an argument of the current hierarchy pointer, or 0 to start at the root. -- -- Warning: Uses recursion to find the next parent's sibling's child (game might not -- use it)! -- -- By Powerline -------------------------------------------------------------------------------------- function GetNextConnectHierarchyPtr(pHierarchyConnect) if pHierarchyConnect > 0 then -- Either child or sibling pHierarchyConnectTmp = memory.readdword(pHierarchyConnect + 0x4) if pHierarchyConnectTmp == 0 then pHierarchyConnectTmp = memory.readdword(pHierarchyConnect + 0xE) if pHierarchyConnectTmp == 0 then pHierarchyConnect = 0 -- Recursive into the parent's sibling's child pHierarchyConnectTmp = memory.readdword(pHierarchyConnect + 0) if pHierarchyConnectTmp == 0 then pHierarchyConnectTmp = memory.readdword(pHierarchyConnect + 0xE) if pHierarchyConnectTmp == 0 then pHierarchyConnect = GetNextConnectPtr(pHierarchyConnectTmp) end end else -- Return next sibling if available pHierarchyConnect = pHierarchyConnectTmp end else -- Return next child if available pHierarchyConnect = pHierarchyConnectTmp end else -- Return root if available pHierarchyConnect = memory.readdword(0x208FB0C) end return pHierarchyConnect end -------------------------------------------------------------------------------------- -- GetNextExecuteLinkPtr() -------------------------------------------------------------------------------------- -- Get the next reordered execute link pointer in the list. -- -- Takes an argument of the current link pointer, or 0 to start at the root. -- -- By Powerline -------------------------------------------------------------------------------------- function GetNextExecuteLinkPtr(pLinkExecute) if pLinkExecute > 0 then -- Return next link if available pLinkExecute = memory.readdword(pLinkExecute + 0x4) else -- Return root if available pLinkExecute = memory.readdword(0x208FB18) end return pLinkExecute end -------------------------------------------------------------------------------------- -- GetNextDrawLinkPtr() -------------------------------------------------------------------------------------- -- Get the next reordered draw link pointer in the list. -- -- Takes an argument of the current link pointer, or 0 to start at the root. -- -- By Powerline -------------------------------------------------------------------------------------- function GetNextDrawLinkPtr(pLinkDraw) if pLinkDraw > 0 then -- Return next link if available pLinkDraw = memory.readdword(pLinkDraw + 0x4) else -- Return root if available pLinkDraw = memory.readdword(0x208FB38) end return pLinkDraw end -------------------------------------------------------------------------------------- -- GetNextComplexColliderLinkPtr() -------------------------------------------------------------------------------------- -- -- By Treeki -------------------------------------------------------------------------------------- function GetNextComplexColliderLinkPtr(pLinkComplexCollider) if pLinkComplexCollider > 0 then -- Return next link if available pLinkComplexCollider = memory.readdword(pLinkComplexCollider + 0xC) else -- Return root if available pLinkComplexCollider = memory.readdword(0x20CAAC8) end return pLinkComplexCollider end -------------------------------------------------------------------------------------- -- GetNextClimbableColliderLinkPtr() -------------------------------------------------------------------------------------- -- -- By Treeki -------------------------------------------------------------------------------------- function GetNextClimbableColliderLinkPtr(pLinkClimbableCollider) if pLinkClimbableCollider > 0 then -- Return next link if available pLinkClimbableCollider = memory.readdword(pLinkClimbableCollider + 0x8) else -- Return root if available pLinkClimbableCollider = memory.readdword(0x208AE64) end return pLinkClimbableCollider end -------------------------------------------------------------------------------------- -- GetNextMiscColliderLinkPtr() -------------------------------------------------------------------------------------- -- -- By Treeki -------------------------------------------------------------------------------------- function GetNextMiscColliderLinkPtr(pLinkMiscCollider) if pLinkMiscCollider > 0 then -- Return next link if available pLinkMiscCollider = memory.readdword(pLinkMiscCollider + 0x8) else -- Return root if available pLinkMiscCollider = memory.readdword(0x208AE94) end return pLinkMiscCollider end -------------------------------------------------------------------------------------- -- GetNextSolidColliderLinkPtr() -------------------------------------------------------------------------------------- -- -- By Treeki -------------------------------------------------------------------------------------- function GetNextSolidColliderLinkPtr(pLinkSolidCollider) if pLinkSolidCollider > 0 then -- Return next link if available pLinkSolidCollider = memory.readdword(pLinkSolidCollider + 0x4) else -- Return root if available pLinkSolidCollider = memory.readdword(0x20CABE8) end return pLinkSolidCollider end -------------------------------------------------------------------------------------- -- Fix12ToFloat() -------------------------------------------------------------------------------------- -- Converts n.12 fixed point into a floating point value -- -- By Powerline -------------------------------------------------------------------------------------- function Fix12ToFloat(fix12) return fix12 / 4096.0 end -------------------------------------------------------------------------------------- -- CacheSetNow() -------------------------------------------------------------------------------------- -- Sets the value stored in the cache now -- -- By Powerline -------------------------------------------------------------------------------------- function CacheSetNow(var, start, set) var[start + 0] = set end -------------------------------------------------------------------------------------- -- CacheGetNow() -------------------------------------------------------------------------------------- -- Gets the value stored in the cache now -- -- By Powerline -------------------------------------------------------------------------------------- function CacheGetNow(var, start) return var[start + 0] end -------------------------------------------------------------------------------------- -- CacheGetObjLater() -------------------------------------------------------------------------------------- -- Gets the value stored in the cache for later -- -- By Powerline -------------------------------------------------------------------------------------- function CacheGetObjLater(var, start) return var[start + (NUM_FRAMES_OBJ - 1)] end -------------------------------------------------------------------------------------- -- CacheVarFrameDown() -------------------------------------------------------------------------------------- -- Caches a value downwards in an array -- -- By Powerline -------------------------------------------------------------------------------------- function CacheVarFrameDown(var, num, start) for a = 0, (num - 1) do b = a + 1 var[start + a] = var[start + b] end end -------------------------------------------------------------------------------------- -- CacheVarFrameUp() -------------------------------------------------------------------------------------- -- Caches a value upwards in an array -- -- By Powerline -------------------------------------------------------------------------------------- function CacheVarFrameUp(var, num, start) for a = (num - 2), 0, -1 do b = a + 1 var[start + b] = var[start + a] end end -------------------------------------------------------------------------------------- -- CacheVarInit() -------------------------------------------------------------------------------------- -- Initializes an array for cache -- -- By Powerline -------------------------------------------------------------------------------------- function CacheVarInit(var, num, entries) for a = 0, (num * entries) do var[a] = 0 end end ------------- -- Globals -- ------------- f12CameraX = {} CacheVarInit(f12CameraX, NUM_FRAMES_OBJ, 1) f12CameraY = {} CacheVarInit(f12CameraY, NUM_FRAMES_OBJ, 1) f12ZoomXY = {} CacheVarInit(f12ZoomXY, NUM_FRAMES_OBJ, 1) f12WrapX = {} CacheVarInit(f12WrapX, NUM_FRAMES_OBJ, 1) pProfExecThis = {} CacheVarInit(pProfExecThis, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) wProfExecName = {} CacheVarInit(wProfExecName, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) bProfExecType = {} CacheVarInit(bProfExecType, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) if SHOW_HITBOX ~= 0 then bProfExecHitbox = {} CacheVarInit(bProfExecHitbox, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) end if SHOW_PLATFORM ~= 0 then bProfExecPlatform = {} CacheVarInit(bProfExecPlatform, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) end if SHOW_SOLID ~= 0 then bProfExecSolid = {} CacheVarInit(bProfExecSolid, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) end if SHOW_SENSOR ~= 0 then bProfExecSensor = {} CacheVarInit(bProfExecSensor, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) end f12ProfX = {} CacheVarInit(f12ProfX, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12ProfY = {} CacheVarInit(f12ProfY, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) if SHOW_HITBOX ~= 0 then f12ProfBBX = {} CacheVarInit(f12ProfBBX, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12ProfBBY = {} CacheVarInit(f12ProfBBY, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12ProfBBW = {} CacheVarInit(f12ProfBBW, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12ProfBBH = {} CacheVarInit(f12ProfBBH, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12ProfTrp0 = {} CacheVarInit(f12ProfTrp0, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12ProfTrp1 = {} CacheVarInit(f12ProfTrp1, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12ProfTrp2 = {} CacheVarInit(f12ProfTrp2, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12ProfTrp3 = {} CacheVarInit(f12ProfTrp3, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) bCollType = {} CacheVarInit(bCollType, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) end if SHOW_PLATFORM ~= 0 then f12PlatformLeftX = {} CacheVarInit(f12PlatformLeftX, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12PlatformLeftY = {} CacheVarInit(f12PlatformLeftY, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12PlatformRightX = {} CacheVarInit(f12PlatformRightX, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12PlatformRightY = {} CacheVarInit(f12PlatformRightY, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12PlatformRotation = {} CacheVarInit(f12PlatformRotation, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) end if SHOW_SOLID ~= 0 then f12SolidProfX = {} CacheVarInit(f12SolidProfX, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SolidProfY = {} CacheVarInit(f12SolidProfY, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SolidLeft = {} CacheVarInit(f12SolidLeft, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SolidTop = {} CacheVarInit(f12SolidTop, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SolidRight = {} CacheVarInit(f12SolidRight, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SolidBottom = {} CacheVarInit(f12SolidBottom, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) end if SHOW_SENSOR ~= 0 then f12SensorProfX = {} CacheVarInit(f12SensorProfX, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SensorProfY = {} CacheVarInit(f12SensorProfY, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) dwSensorBelowFlags = {} CacheVarInit(dwSensorBelowFlags, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SensorBelowX = {} CacheVarInit(f12SensorBelowX, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SensorBelowY = {} CacheVarInit(f12SensorBelowY, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SensorBelowAt = {} CacheVarInit(f12SensorBelowAt, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) dwSensorAboveFlags = {} CacheVarInit(dwSensorAboveFlags, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SensorAboveX = {} CacheVarInit(f12SensorAboveX, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SensorAboveY = {} CacheVarInit(f12SensorAboveY, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SensorAboveAt = {} CacheVarInit(f12SensorAboveAt, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) dwSensorAdjacentFlags = {} CacheVarInit(dwSensorAdjacentFlags, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SensorAdjacentX = {} CacheVarInit(f12SensorAdjacentX, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SensorAdjacentY = {} CacheVarInit(f12SensorAdjacentY, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) f12SensorAdjacentAt = {} CacheVarInit(f12SensorAdjacentAt, NUM_FRAMES_OBJ, NUM_OBJ_ENTRIES) end -- Frame drawing nFrameRef = -1 nFrameCurrent = 0 local function NSMBFrameTick() nFrameRef = nFrameRef + 1 -- memory.writedword(0x2107e44, 0xe12dff1e) -- memory.writedword(0x21b71c0, 0x6001c001) -- memory.writedword(0x21b71c4, -0x20000) -- memory.writedword(0x21b71c8, 0x20000) -- memory.writedword(0x21b71dc, 0x20000) -- memory.writedword(0x21b71d4, 0x10001) -- memory.writedword(0x21b71d8, 0x10000) end emu.registerbefore(NSMBFrameTick) local function GetProfString(ProfName) if ProfName == 0x003 then return "STAGE" elseif ProfName == 0x015 then return "PLAYER" elseif ProfName == 0x13C then return "CAMERA" elseif ProfName == 0x145 then return "LASTACTOR_STAGE" end return bit.tohex(ProfName, -3) end collTypeNames = { [0] = 'Rect', [1] = 'Round', [2] = 'Trapezoid Verti', [3] = 'Trapezoid Horiz' } local function GetHitboxString(zHitbox) if zHitbox > 0 then if zHitbox < 5 then return string.format("Hitbox %s", collTypeNames[zHitbox - 1]) else return "Hitbox" end end return "" end local function GetPlatformString(zPlatform, zRotation) if zPlatform > 0 then return string.format("Platform:%ddeg", zRotation) end return "" end local function GetSolidString(zSolid) if zSolid > 0 then return string.format("Solid") end return "" end MaxProcessed = 0 local function DoCacheDraw() TextLine = 0 Processed = 0 f12ScreenWrapX = CacheGetObjLater(f12WrapX, 0) fCameraX = Fix12ToFloat(bit.band(f12ScreenWrapX, CacheGetObjLater(f12CameraX, 0))) fCameraY = Fix12ToFloat(CacheGetObjLater(f12CameraY, 0)) fZoomXY = 1 / Fix12ToFloat(CacheGetObjLater(f12ZoomXY, 0)) for i = 0, (NUM_OBJ_ENTRIES - 1) do j = i * NUM_FRAMES_OBJ bHitbox = 0 bPlatform = 0 bSolid = 0 fDegRotation = 0 pPaintExecProf = CacheGetObjLater(pProfExecThis, j) if pPaintExecProf > 0 then if SHOW_HITBOX ~= 0 then -- Is this a hitbox? if CacheGetObjLater(bProfExecHitbox, j) > 0 then bHitbox = 1 + CacheGetObjLater(bCollType, j) -- Calculate hitbox screen position, counting for relative camera, zoom, and horizontal stage wrapping f12WrappedX = bit.band(f12ScreenWrapX, CacheGetObjLater(f12ProfX, j)) fProcScreenX = (Fix12ToFloat(f12WrappedX) - fCameraX) fProcScreenY = (Fix12ToFloat(CacheGetObjLater(f12ProfY, j)) - fCameraY) fBBOffsetX = Fix12ToFloat(CacheGetObjLater(f12ProfBBX, j)) fBBOffsetY = Fix12ToFloat(CacheGetObjLater(f12ProfBBY, j)) fBBWidth = Fix12ToFloat(CacheGetObjLater(f12ProfBBW, j)) fBBHeight = Fix12ToFloat(CacheGetObjLater(f12ProfBBH, j)) -- Let's draw trapezoids / Powerline if bHitbox >= 3 then fTpr0 = Fix12ToFloat(CacheGetObjLater(f12ProfTrp0, j)) fTpr1 = Fix12ToFloat(CacheGetObjLater(f12ProfTrp1, j)) fTpr2 = Fix12ToFloat(CacheGetObjLater(f12ProfTrp2, j)) fTpr3 = Fix12ToFloat(CacheGetObjLater(f12ProfTrp3, j)) if bHitbox == 3 then -- Vertical fTopLeftX = (fProcScreenX + fBBOffsetX - fBBWidth) * fZoomXY fTopLeftY = (fProcScreenY + fTpr1) * fZoomXY + 192 fTopRightX = (fProcScreenX + fBBOffsetX + fBBWidth) * fZoomXY fTopRightY = (fProcScreenY + fTpr3) * fZoomXY + 192 fBottomLeftX = (fProcScreenX + fBBOffsetX - fBBWidth) * fZoomXY fBottomLeftY = (fProcScreenY + fTpr0) * fZoomXY + 192 fBottomRightX = (fProcScreenX + fBBOffsetX + fBBWidth) * fZoomXY fBottomRightY = (fProcScreenY + fTpr2) * fZoomXY + 192 else -- Horizontal fTopLeftX = (fProcScreenX + fTpr0) * fZoomXY fTopLeftY = (fProcScreenY + fBBOffsetY - fBBHeight) * fZoomXY + 192 fTopRightX = (fProcScreenX + fTpr1) * fZoomXY fTopRightY = (fProcScreenY + fBBOffsetY - fBBHeight) * fZoomXY + 192 fBottomLeftX = (fProcScreenX + fTpr2) * fZoomXY fBottomLeftY = (fProcScreenY + fBBOffsetY + fBBHeight) * fZoomXY + 192 fBottomRightX = (fProcScreenX + fTpr3) * fZoomXY fBottomRightY = (fProcScreenY + fBBOffsetY + fBBHeight) * fZoomXY + 192 end -- Top gui.line( fTopLeftX, GetActiveLCDY() + fTopLeftY, fTopRightX, GetActiveLCDY() + fTopRightY, COLOR_HITBOX_OUT) -- Bottom gui.line( fBottomLeftX, GetActiveLCDY() + fBottomLeftY, fBottomRightX, GetActiveLCDY() + fBottomRightY, COLOR_HITBOX_OUT) -- Left gui.line( fTopLeftX, GetActiveLCDY() + fTopLeftY, fBottomLeftX, GetActiveLCDY() + fBottomLeftY, COLOR_HITBOX_OUT) -- Right gui.line( fTopRightX, GetActiveLCDY() + fTopRightY, fBottomRightX, GetActiveLCDY() + fBottomRightY, COLOR_HITBOX_OUT) -- Let's draw a nice circle /Powerline elseif bHitbox == 2 then for a = 0, 32 do b = a * 0.196350 -- pi*2 / 32 fRoundX2 = (fProcScreenX + fBBOffsetX + (math.cos(b) * fBBWidth)) * fZoomXY fRoundY2 = (fProcScreenY + fBBOffsetY + (math.sin(b) * fBBHeight)) * fZoomXY + 192 if a ~= 0 then gui.line( fRoundX1, GetActiveLCDY() + fRoundY1, fRoundX2, GetActiveLCDY() + fRoundY2, COLOR_HITBOX_OUT) end fRoundX1 = fRoundX2 fRoundY1 = fRoundY2 end else fProcScreenX = (fProcScreenX + fBBOffsetX) * fZoomXY fProcScreenY = (fProcScreenY + fBBOffsetY) * fZoomXY fProcScreenY = fProcScreenY + 192 fBBWidth = fBBWidth * fZoomXY fBBHeight = fBBHeight * fZoomXY gui.box( fProcScreenX - fBBWidth, GetActiveLCDY() + fProcScreenY - fBBHeight, fProcScreenX + fBBWidth, GetActiveLCDY() + fProcScreenY + fBBHeight, COLOR_HITBOX_IN, COLOR_HITBOX_OUT) end end end if SHOW_PLATFORM ~= 0 then -- Is this a platform? if CacheGetObjLater(bProfExecPlatform, j) > 0 then -- Calculate platform screen position, counting for relative camera, zoom, and horizontal stage wrapping bPlatform = CacheGetObjLater(bProfExecPlatform, j) fDegRotation = CacheGetObjLater(f12PlatformRotation, j) * 0.0054931640625 f12WrappedX = bit.band(f12ScreenWrapX, CacheGetObjLater(f12PlatformLeftX, j)) f12WrappedX2 = bit.band(f12ScreenWrapX, CacheGetObjLater(f12PlatformRightX, j)) if f12WrappedX2 < f12WrappedX then f12WrappedX2 = f12WrappedX2 + (f12ScreenWrapX + 1) end fLeftX = (Fix12ToFloat(f12WrappedX) - fCameraX) * fZoomXY fLeftY = (Fix12ToFloat(CacheGetObjLater(f12PlatformLeftY, j)) - fCameraY) * fZoomXY + 192 fRightX = (Fix12ToFloat(f12WrappedX2) - fCameraX) * fZoomXY fRightY = (Fix12ToFloat(CacheGetObjLater(f12PlatformRightY, j)) - fCameraY) * fZoomXY + 192 gui.line( fLeftX, GetActiveLCDY() + fLeftY, fRightX, GetActiveLCDY() + fRightY, COLOR_PLATFORM) end end if SHOW_SOLID ~= 0 then -- Is this a solid? if CacheGetObjLater(bProfExecSolid, j) > 0 then bSolid = 1 -- Calculate hitbox screen position, counting for relative camera, zoom, and horizontal stage wrapping f12WrappedX = bit.band(f12ScreenWrapX, CacheGetObjLater(f12SolidProfX, j)) fProcScreenX = (Fix12ToFloat(f12WrappedX) - fCameraX) fProcScreenY = (Fix12ToFloat(CacheGetObjLater(f12SolidProfY, j)) - fCameraY) fBBLeft = (Fix12ToFloat(CacheGetObjLater(f12SolidLeft, j)) + fProcScreenX) * fZoomXY fBBTop = (Fix12ToFloat(CacheGetObjLater(f12SolidTop, j)) + fProcScreenY) * fZoomXY + 192 fBBRight = (Fix12ToFloat(CacheGetObjLater(f12SolidRight, j)) + fProcScreenX) * fZoomXY fBBBottom = (Fix12ToFloat(CacheGetObjLater(f12SolidBottom, j)) + fProcScreenY) * fZoomXY + 192 gui.box( fBBLeft, GetActiveLCDY() + fBBTop, fBBRight, GetActiveLCDY() + fBBBottom, COLOR_SOLID_IN, COLOR_SOLID_OUT) end end -- Sensors are drawn last to stay on top if SHOW_SENSOR ~= 0 then bSensorUses = CacheGetObjLater(bProfExecSensor, j) -- Is this a sensor? if bSensorUses > 0 then -- Draw below sensor? if bit.band(bSensorUses, 0x1) ~= 0 then dwSensorFlags = CacheGetObjLater(dwSensorBelowFlags, j) if bit.band(dwSensorFlags, 0x1) == 0 then -- Point sensor fPointX = (Fix12ToFloat(bit.band(f12ScreenWrapX, CacheGetObjLater(f12SensorProfX, j) + CacheGetObjLater(f12SensorBelowX, j))) - fCameraX) * fZoomXY fPointY = (Fix12ToFloat(CacheGetObjLater(f12SensorProfY, j) + CacheGetObjLater(f12SensorBelowY, j)) - fCameraY) * fZoomXY + 192 gui.pixel( fPointX, GetActiveLCDY() + fPointY, COLOR_SENSOR_BELOW) else -- Line sensor f12WrappedX = bit.band(f12ScreenWrapX, CacheGetObjLater(f12SensorProfX, j) + CacheGetObjLater(f12SensorBelowX, j)) f12WrappedX2 = bit.band(f12ScreenWrapX, CacheGetObjLater(f12SensorProfX, j) + CacheGetObjLater(f12SensorBelowY, j)) if f12WrappedX2 < f12WrappedX then f12WrappedX2 = f12WrappedX2 + (f12ScreenWrapX + 1) end fLineX1 = (Fix12ToFloat(f12WrappedX) - fCameraX) * fZoomXY fLineX2 = (Fix12ToFloat(f12WrappedX2) - fCameraX) * fZoomXY fLineY = (Fix12ToFloat(CacheGetObjLater(f12SensorProfY, j) + CacheGetObjLater(f12SensorBelowAt, j)) - fCameraY) * fZoomXY + 192 gui.line( fLineX1, GetActiveLCDY() + fLineY, fLineX2, GetActiveLCDY() + fLineY, COLOR_SENSOR_BELOW) end end -- Draw above sensor? if bit.band(bSensorUses, 0x2) ~= 0 then dwSensorFlags = CacheGetObjLater(dwSensorAboveFlags, j) if bit.band(dwSensorFlags, 0x1) == 0 then -- Point sensor fPointX = (Fix12ToFloat(bit.band(f12ScreenWrapX, CacheGetObjLater(f12SensorProfX, j) + CacheGetObjLater(f12SensorAboveX, j))) - fCameraX) * fZoomXY fPointY = (Fix12ToFloat(CacheGetObjLater(f12SensorProfY, j) - CacheGetObjLater(f12SensorAboveY, j)) - fCameraY) * fZoomXY + 192 gui.pixel( fPointX, GetActiveLCDY() + fPointY, COLOR_SENSOR_ABOVE) else -- Line sensor f12WrappedX = bit.band(f12ScreenWrapX, CacheGetObjLater(f12SensorProfX, j) + CacheGetObjLater(f12SensorAboveX, j)) f12WrappedX2 = bit.band(f12ScreenWrapX, CacheGetObjLater(f12SensorProfX, j) + CacheGetObjLater(f12SensorAboveY, j)) if f12WrappedX2 < f12WrappedX then f12WrappedX2 = f12WrappedX2 + (f12ScreenWrapX + 1) end fLineX1 = (Fix12ToFloat(f12WrappedX) - fCameraX) * fZoomXY fLineX2 = (Fix12ToFloat(f12WrappedX2) - fCameraX) * fZoomXY fLineY = (Fix12ToFloat(CacheGetObjLater(f12SensorProfY, j) - CacheGetObjLater(f12SensorAboveAt, j)) - fCameraY) * fZoomXY + 192 gui.line( fLineX1, GetActiveLCDY() + fLineY, fLineX2, GetActiveLCDY() + fLineY, COLOR_SENSOR_ABOVE) end end -- Draw adjacent sensor? if bit.band(bSensorUses, 0x4) ~= 0 then dwSensorFlags = CacheGetObjLater(dwSensorAdjacentFlags, j) if bit.band(dwSensorFlags, 0x1) == 0 then -- Point sensor fPointX = (Fix12ToFloat(bit.band(f12ScreenWrapX, CacheGetObjLater(f12SensorProfX, j) - CacheGetObjLater(f12SensorAdjacentX, j))) - fCameraX) * fZoomXY fPointX2 = (Fix12ToFloat(bit.band(f12ScreenWrapX, CacheGetObjLater(f12SensorProfX, j) + CacheGetObjLater(f12SensorAdjacentX, j))) - fCameraX) * fZoomXY fPointY = (Fix12ToFloat(CacheGetObjLater(f12SensorProfY, j) - CacheGetObjLater(f12SensorAdjacentY, j)) - fCameraY) * fZoomXY + 192 gui.pixel( fPointX, GetActiveLCDY() + fPointY, COLOR_SENSOR_LEFT) gui.pixel( fPointX2, GetActiveLCDY() + fPointY, COLOR_SENSOR_RIGHT) else -- Line sensor f12WrappedX = bit.band(f12ScreenWrapX, CacheGetObjLater(f12SensorProfX, j) - CacheGetObjLater(f12SensorAdjacentAt, j)) f12WrappedX2 = bit.band(f12ScreenWrapX, CacheGetObjLater(f12SensorProfX, j) + CacheGetObjLater(f12SensorAdjacentAt, j)) if f12WrappedX2 < f12WrappedX then f12WrappedX2 = f12WrappedX2 + (f12ScreenWrapX + 1) end fLineX1 = (Fix12ToFloat(f12WrappedX) - fCameraX) * fZoomXY fLineX2 = (Fix12ToFloat(f12WrappedX2) - fCameraX) * fZoomXY fLineY1 = (Fix12ToFloat(CacheGetObjLater(f12SensorProfY, j) - CacheGetObjLater(f12SensorAdjacentX, j)) - fCameraY) * fZoomXY + 192 fLineY2 = (Fix12ToFloat(CacheGetObjLater(f12SensorProfY, j) - CacheGetObjLater(f12SensorAdjacentY, j)) - fCameraY) * fZoomXY + 192 gui.line( fLineX1, GetActiveLCDY() + fLineY1, fLineX1, GetActiveLCDY() + fLineY2, COLOR_SENSOR_LEFT) gui.line( fLineX2, GetActiveLCDY() + fLineY1, fLineX2, GetActiveLCDY() + fLineY2, COLOR_SENSOR_RIGHT) end end end end if pPaintExecProf ~= 0xDEAD0000 then if TextLine < (19 * 10) then gui.text(0, TextLine, string.format("%08X %01d %s %s%s%s", pPaintExecProf, CacheGetObjLater(bProfExecType, j), GetProfString(CacheGetObjLater(wProfExecName, j)), GetHitboxString(bHitbox), GetPlatformString(bPlatform, fDegRotation), GetSolidString(bSolid)), "#AAE000FF", "#000000FF") end if TextLine == (18 * 10) then gui.text(236, TextLine, "...", "#AAE000FF", "#000000FF") end TextLine = TextLine + 10 end Processed = Processed + 1 end end if Processed > MaxProcessed then MaxProcessed = Processed end gui.text(142, 0, string.format("Space used: %03d/%03d", MaxProcessed, NUM_OBJ_ENTRIES), "#000000FF", "#AAE000FF") end offsetsForSensorClass = { 0x1D0, 0x608, 0x654, 0xC4C, 0x564, 0x42C, 0x5C0 } local function NSMBFrameDraw() -- The emulator draws a new frame when redrawing is needed. We need to find out when it is actually the game that is drawing -- so that we can have the latest complete frame info stored to be shown later if nFrameRef == nFrameCurrent then DoCacheDraw() return end nFrameCurrent = nFrameRef -- Get the camera info for this frame to be shown NUM_FRAMES_OBJ frames later CacheVarFrameUp(f12CameraX, NUM_FRAMES_OBJ, 0) CacheSetNow(f12CameraX, 0, memory.readdwordsigned(0x21B6964)) CacheVarFrameUp(f12CameraY, NUM_FRAMES_OBJ, 0) CacheSetNow(f12CameraY, 0, -memory.readdwordsigned(0x21B6968)) CacheVarFrameUp(f12ZoomXY, NUM_FRAMES_OBJ, 0) CacheSetNow(f12ZoomXY, 0, memory.readdwordsigned(0x20CADB4)) CacheVarFrameUp(f12WrapX, NUM_FRAMES_OBJ, 0) CacheSetNow(f12WrapX, 0, memory.readdword(0x2085AA4)) -- Move all info one frame into the past so we can show it NUM_FRAMES_OBJ frames later for i = 0, NUM_OBJ_ENTRIES do j = i * NUM_FRAMES_OBJ CacheVarFrameUp(pProfExecThis, NUM_FRAMES_OBJ, j) CacheVarFrameUp(wProfExecName, NUM_FRAMES_OBJ, j) CacheVarFrameUp(bProfExecType, NUM_FRAMES_OBJ, j) if SHOW_HITBOX ~= 0 then CacheVarFrameUp(bProfExecHitbox, NUM_FRAMES_OBJ, j) end if SHOW_PLATFORM ~= 0 then CacheVarFrameUp(bProfExecPlatform, NUM_FRAMES_OBJ, j) end if SHOW_SOLID ~= 0 then CacheVarFrameUp(bProfExecSolid, NUM_FRAMES_OBJ, j) end if SHOW_SENSOR ~= 0 then CacheVarFrameUp(bProfExecSensor, NUM_FRAMES_OBJ, j) end CacheVarFrameUp(f12ProfX, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12ProfY, NUM_FRAMES_OBJ, j) if SHOW_HITBOX ~= 0 then CacheVarFrameUp(f12ProfBBX, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12ProfBBY, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12ProfBBW, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12ProfBBH, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12ProfTrp0, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12ProfTrp1, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12ProfTrp2, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12ProfTrp3, NUM_FRAMES_OBJ, j) CacheVarFrameUp(bCollType, NUM_FRAMES_OBJ, j) end if SHOW_PLATFORM ~= 0 then CacheVarFrameUp(f12PlatformLeftX, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12PlatformLeftY, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12PlatformRightX, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12PlatformRightY, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12PlatformRotation, NUM_FRAMES_OBJ, j) end if SHOW_SOLID ~= 0 then CacheVarFrameUp(f12SolidProfX, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SolidProfY, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SolidLeft, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SolidTop, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SolidRight, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SolidBottom, NUM_FRAMES_OBJ, j) end if SHOW_SENSOR ~= 0 then CacheVarFrameUp(f12SensorProfX, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SensorProfY, NUM_FRAMES_OBJ, j) CacheVarFrameUp(dwSensorBelowFlags, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SensorBelowX, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SensorBelowY, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SensorBelowAt, NUM_FRAMES_OBJ, j) CacheVarFrameUp(dwSensorAboveFlags, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SensorAboveX, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SensorAboveY, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SensorAboveAt, NUM_FRAMES_OBJ, j) CacheVarFrameUp(dwSensorAdjacentFlags, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SensorAdjacentX, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SensorAdjacentY, NUM_FRAMES_OBJ, j) CacheVarFrameUp(f12SensorAdjacentAt, NUM_FRAMES_OBJ, j) end end -- Go through ordered execution list pLinkExecute = GetNextExecuteLinkPtr(0) j = 0 i = 0 while (pLinkExecute > 0) do pProfExec = memory.readdword(pLinkExecute + 0x8) CacheSetNow(pProfExecThis, j, pProfExec) CacheSetNow(wProfExecName, j, memory.readword(pProfExec + 0xC)) CacheSetNow(bProfExecType, j, memory.readbyte(pProfExec + 0x12)) if SHOW_HITBOX ~= 0 then CacheSetNow(bProfExecHitbox, j, 0) end if SHOW_PLATFORM ~= 0 then CacheSetNow(bProfExecPlatform, j, 0) end if SHOW_SOLID ~= 0 then CacheSetNow(bProfExecSolid, j, 0) end if SHOW_SENSOR ~= 0 then CacheSetNow(bProfExecSensor, j, 0) end j = j + NUM_FRAMES_OBJ i = i + 1 -- Find the next one pLinkExecute = GetNextExecuteLinkPtr(pLinkExecute) end LastExecIndex = i for i = LastExecIndex, NUM_OBJ_ENTRIES do j = i * NUM_FRAMES_OBJ CacheSetNow(pProfExecThis, j, 0) if SHOW_HITBOX ~= 0 then CacheSetNow(bProfExecHitbox, j, 0) end if SHOW_PLATFORM ~= 0 then CacheSetNow(bProfExecPlatform, j, 0) end if SHOW_SOLID ~= 0 then CacheSetNow(bProfExecSolid, j, 0) end if SHOW_SENSOR ~= 0 then CacheSetNow(bProfExecSensor, j, 0) end end if SHOW_HITBOX ~= 0 then -- Go through all complex colliders pCColl = GetNextComplexColliderLinkPtr(0) j = 0 i = 0 while pCColl > 0 do pCColProfThis = memory.readdword(pCColl + 0x4) for k = 0, NUM_OBJ_ENTRIES do l = k * NUM_FRAMES_OBJ pProfExec = CacheGetNow(pProfExecThis, l) if pProfExec > 0 then if pProfExec == pCColProfThis then -- Already had one before? Then find an empty slot if CacheGetNow(bProfExecHitbox, l) > 0 then for a = LastExecIndex, NUM_OBJ_ENTRIES do b = a * NUM_FRAMES_OBJ if CacheGetNow(pProfExecThis, b) == 0 then l = b CacheSetNow(pProfExecThis, l, 0xDEAD0000) CacheSetNow(bProfExecHitbox, l, 1) CacheSetNow(f12ProfX, l, memory.readdwordsigned(pCColProfThis + 0x60)) CacheSetNow(f12ProfY, l, -memory.readdwordsigned(pCColProfThis + 0x64)) CacheSetNow(f12ProfBBX, l, memory.readdwordsigned(pCColl + 0x14)) CacheSetNow(f12ProfBBY, l, -memory.readdwordsigned(pCColl + 0x18)) CacheSetNow(f12ProfBBW, l, memory.readdwordsigned(pCColl + 0x1C)) CacheSetNow(f12ProfBBH, l, memory.readdwordsigned(pCColl + 0x20)) CacheSetNow(f12ProfTrp0, l, memory.readdwordsigned(pCColl + 0x8C)) CacheSetNow(f12ProfTrp1, l, memory.readdwordsigned(pCColl + 0x90)) CacheSetNow(f12ProfTrp2, l, memory.readdwordsigned(pCColl + 0x94)) CacheSetNow(f12ProfTrp3, l, memory.readdwordsigned(pCColl + 0x98)) CacheSetNow(bCollType, l, memory.readbyte(pCColl + 0xAA)) break end end end CacheSetNow(bProfExecHitbox, l, 1) CacheSetNow(f12ProfX, l, memory.readdwordsigned(pCColProfThis + 0x60)) CacheSetNow(f12ProfY, l, -memory.readdwordsigned(pCColProfThis + 0x64)) CacheSetNow(f12ProfBBX, l, memory.readdwordsigned(pCColl + 0x14)) CacheSetNow(f12ProfBBY, l, -memory.readdwordsigned(pCColl + 0x18)) CacheSetNow(f12ProfBBW, l, memory.readdwordsigned(pCColl + 0x1C)) CacheSetNow(f12ProfBBH, l, memory.readdwordsigned(pCColl + 0x20)) CacheSetNow(f12ProfTrp0, l, memory.readdwordsigned(pCColl + 0x8C)) CacheSetNow(f12ProfTrp1, l, memory.readdwordsigned(pCColl + 0x90)) CacheSetNow(f12ProfTrp2, l, memory.readdwordsigned(pCColl + 0x94)) CacheSetNow(f12ProfTrp3, l, memory.readdwordsigned(pCColl + 0x98)) CacheSetNow(bCollType, l, memory.readbyte(pCColl + 0xAA)) end end end j = j + NUM_FRAMES_OBJ i = i + 1 -- Find the next one pCColl = GetNextComplexColliderLinkPtr(pCColl) end end if SHOW_PLATFORM ~= 0 then -- Go through all misc colliders pBColl = GetNextMiscColliderLinkPtr(0) j = 0 i = 0 while pBColl > 0 do pBColProfThis = memory.readdword(pBColl + 0x4) for k = 0, NUM_OBJ_ENTRIES do l = k * NUM_FRAMES_OBJ pProfExec = CacheGetNow(pProfExecThis, l) if pProfExec > 0 then if pProfExec == pBColProfThis then -- Already had one before? Then find an empty slot if CacheGetNow(bProfExecPlatform, l) > 0 then for a = LastExecIndex, NUM_OBJ_ENTRIES do b = a * NUM_FRAMES_OBJ if CacheGetNow(pProfExecThis, b) == 0 then l = b CacheSetNow(pProfExecThis, l, 0xDEAD0000) CacheSetNow(bProfExecPlatform, l, 1 + memory.readbyte(pBColl + 0x50)) CacheSetNow(f12PlatformRotation, l, memory.readword(pBColl + 0x4C)) CacheSetNow(f12PlatformLeftX, l, memory.readdwordsigned(pBColl + 0x24)) CacheSetNow(f12PlatformLeftY, l, -memory.readdwordsigned(pBColl + 0x28)) CacheSetNow(f12PlatformRightX, l, memory.readdwordsigned(pBColl + 0x18)) CacheSetNow(f12PlatformRightY, l, -memory.readdwordsigned(pBColl + 0x1C)) break end end end CacheSetNow(bProfExecPlatform, l, 1 + memory.readbyte(pBColl + 0x50)) CacheSetNow(f12PlatformRotation, l, memory.readword(pBColl + 0x4C)) CacheSetNow(f12PlatformLeftX, l, memory.readdwordsigned(pBColl + 0x24)) CacheSetNow(f12PlatformLeftY, l, -memory.readdwordsigned(pBColl + 0x28)) CacheSetNow(f12PlatformRightX, l, memory.readdwordsigned(pBColl + 0x18)) CacheSetNow(f12PlatformRightY, l, -memory.readdwordsigned(pBColl + 0x1C)) end end end j = j + NUM_FRAMES_OBJ i = i + 1 -- Find the next one pBColl = GetNextMiscColliderLinkPtr(pBColl) end end if SHOW_SOLID ~= 0 then -- Go through all solid colliders pSColl = GetNextSolidColliderLinkPtr(0) j = 0 i = 0 while pSColl > 0 do pSColProfThis = memory.readdword(pSColl + 0x0) for k = 0, NUM_OBJ_ENTRIES do l = k * NUM_FRAMES_OBJ pProfExec = CacheGetNow(pProfExecThis, l) if pProfExec > 0 then if pProfExec == pSColProfThis then -- Already had one before? Then find an empty slot if CacheGetNow(bProfExecSolid, l) > 0 then for a = LastExecIndex, NUM_OBJ_ENTRIES do b = a * NUM_FRAMES_OBJ if CacheGetNow(pProfExecThis, b) == 0 then l = b CacheSetNow(pProfExecThis, l, 0xDEAD0000) CacheSetNow(bProfExecSolid, l, 1) CacheSetNow(f12SolidProfX, l, memory.readdwordsigned(pSColl + 0x58)) CacheSetNow(f12SolidProfY, l, -memory.readdwordsigned(pSColl + 0x5C)) CacheSetNow(f12SolidLeft, l, memory.readdwordsigned(pSColl + 0x28)) CacheSetNow(f12SolidTop, l, -memory.readdwordsigned(pSColl + 0x2C)) CacheSetNow(f12SolidRight, l, -memory.readdwordsigned(pSColl + 0x34)) CacheSetNow(f12SolidBottom, l, -memory.readdwordsigned(pSColl + 0x38)) break end end end CacheSetNow(bProfExecSolid, l, 1) CacheSetNow(f12SolidProfX, l, memory.readdwordsigned(pSColl + 0x58)) CacheSetNow(f12SolidProfY, l, -memory.readdwordsigned(pSColl + 0x5C)) CacheSetNow(f12SolidLeft, l, memory.readdwordsigned(pSColl + 0x28)) CacheSetNow(f12SolidTop, l, -memory.readdwordsigned(pSColl + 0x2C)) CacheSetNow(f12SolidRight, l, memory.readdwordsigned(pSColl + 0x34)) CacheSetNow(f12SolidBottom, l, -memory.readdwordsigned(pSColl + 0x38)) end end end j = j + NUM_FRAMES_OBJ i = i + 1 -- Find the next one pSColl = GetNextSolidColliderLinkPtr(pSColl) end end if SHOW_SENSOR ~= 0 then -- Go through all sensors (might be multipe in one profile) pDraw = GetNextDrawLinkPtr(0) j = 0 i = 0 while pDraw > 0 do pDrawThis = memory.readdword(pDraw + 0x8) for zz, SensorOffset in pairs(offsetsForSensorClass) do pSensorClass = pDrawThis + SensorOffset if memory.readdword(pSensorClass) == 0x20C7008 then pSensorProfThis = memory.readdword(pSensorClass + 0x4) pBelow = memory.readdword(pSensorClass + 0x8) pAbove = memory.readdword(pSensorClass + 0xC) pAdjacent = memory.readdword(pSensorClass + 0x10) f12SensorX = memory.readdwordsigned(pSensorProfThis + 0x60) f12SensorY = -memory.readdwordsigned(pSensorProfThis + 0x64) for k = 0, NUM_OBJ_ENTRIES do l = k * NUM_FRAMES_OBJ pProfExec = CacheGetNow(pProfExecThis, l) if pProfExec > 0 then if pProfExec == pSensorProfThis then -- Already had one before? Then find an empty slot if CacheGetNow(bProfExecSensor, l) > 0 then for a = LastExecIndex, NUM_OBJ_ENTRIES do b = a * NUM_FRAMES_OBJ if CacheGetNow(pProfExecThis, b) == 0 then l = b CacheSetNow(pProfExecThis, l, 0xDEAD0000) CacheSetNow(f12SensorProfX, l, f12SensorX) CacheSetNow(f12SensorProfY, l, f12SensorY) bSensorUses = 0 if pBelow > 0 then -- Use below sensor for drawing bSensorUses = bit.bor(bSensorUses, 0x1) CacheSetNow(dwSensorBelowFlags, l, memory.readdword(pBelow + 0x0)) CacheSetNow(f12SensorBelowX, l, memory.readdword(pBelow + 0x4)) CacheSetNow(f12SensorBelowY, l, memory.readdword(pBelow + 0x8)) CacheSetNow(f12SensorBelowAt, l, memory.readdword(pBelow + 0xC)) end if pAbove > 0 then -- Use above sensor for drawing bSensorUses = bit.bor(bSensorUses, 0x2) CacheSetNow(dwSensorAboveFlags, l, memory.readdword(pAbove + 0x0)) CacheSetNow(f12SensorAboveX, l, memory.readdword(pAbove + 0x4)) CacheSetNow(f12SensorAboveY, l, memory.readdword(pAbove + 0x8)) CacheSetNow(f12SensorAboveAt, l, memory.readdword(pAbove + 0xC)) end if pAdjacent > 0 then -- Use adjacent sensor for drawing bSensorUses = bit.bor(bSensorUses, 0x4) CacheSetNow(dwSensorAdjacentFlags, l, memory.readdword(pAdjacent + 0x0)) CacheSetNow(f12SensorAdjacentX, l, memory.readdword(pAdjacent + 0x4)) CacheSetNow(f12SensorAdjacentY, l, memory.readdword(pAdjacent + 0x8)) CacheSetNow(f12SensorAdjacentAt, l, memory.readdword(pAdjacent + 0xC)) end CacheSetNow(bProfExecSensor, l, bSensorUses) break end end end CacheSetNow(f12SensorProfX, l, f12SensorX) CacheSetNow(f12SensorProfY, l, f12SensorY) bSensorUses = 0 if pBelow > 0 then -- Use below sensor for drawing bSensorUses = bit.bor(bSensorUses, 0x1) CacheSetNow(dwSensorBelowFlags, l, memory.readdword(pBelow + 0x0)) CacheSetNow(f12SensorBelowX, l, memory.readdword(pBelow + 0x4)) CacheSetNow(f12SensorBelowY, l, memory.readdword(pBelow + 0x8)) CacheSetNow(f12SensorBelowAt, l, memory.readdword(pBelow + 0xC)) end if pAbove > 0 then -- Use above sensor for drawing bSensorUses = bit.bor(bSensorUses, 0x2) --memory.writedword(pAbove + 0x0, bit.band(memory.readdword(pAbove + 0x0), 0xFFFFFFFE)) CacheSetNow(dwSensorAboveFlags, l, memory.readdword(pAbove + 0x0)) CacheSetNow(f12SensorAboveX, l, memory.readdword(pAbove + 0x4)) CacheSetNow(f12SensorAboveY, l, memory.readdword(pAbove + 0x8)) CacheSetNow(f12SensorAboveAt, l, memory.readdword(pAbove + 0xC)) end if pAdjacent > 0 then -- Use adjacent sensor for drawing bSensorUses = bit.bor(bSensorUses, 0x4) --memory.writedword(pAdjacent + 0x0, bit.band(memory.readdword(pAdjacent + 0x0), 0xFFFFFFFE)) CacheSetNow(dwSensorAdjacentFlags, l, memory.readdword(pAdjacent + 0x0)) CacheSetNow(f12SensorAdjacentX, l, memory.readdword(pAdjacent + 0x4)) CacheSetNow(f12SensorAdjacentY, l, memory.readdword(pAdjacent + 0x8)) CacheSetNow(f12SensorAdjacentAt, l, memory.readdword(pAdjacent + 0xC)) end CacheSetNow(bProfExecSensor, l, bSensorUses) end end end end end j = j + NUM_FRAMES_OBJ i = i + 1 -- Find the next one pDraw = GetNextDrawLinkPtr(pDraw) end end DoCacheDraw() end -- Everything is delayed by 3 frames from gui.register() once the game has done a complete frame gui.register(NSMBFrameDraw)