I have seen in various tables that some people are unknowingly getting the instance bases for certain object types but I have a good way to quickly get all object types and their bases/instances.
Similar to the CScripts in the other post, you can iterate through all of the objects when you find their base using the following template table: Once Enabled, you can use the object name as the indexer in your pointers like so:
From the base there are two important parts that need addressing, one is the associated events (step, create, destroy, alarms etc.) and the other is the instances which is what I will be focusing on in this post. Once you get to the base of the object, the number of current instances is located +0x8 from the base of the instance array (which is a linked list by the looks of it) and you index through them by driving down into offset 0x0 as you can see here:
In this case the head of that linked list is at 0xD0 and the tail is at 0xD4 but in other games it could be at 0x38/0x3C. It depends on what the object properties offset is (0x2C or 0x60 for instances at 0x38 and 0xD0 respectively). This means to get to instance 1 you only go down 1 level into 0xD0, for instance 2 you go 2 levels down into 0xD0 and so on.
For games that use multiple instances of the same object (Such as Grim Night which I have posted table for here), you can quickly iterate through the list and set stats or generate records using the following getObjectBase(objName) and getObjectInstance(base,instNum) functions I made:
Code: Select all
function registerObjects(base)
local base = readPointer(base)
local numObjects = readInteger(base+8)-1
if numObjects > 511 then numObjects = 511 end
base = readPointer(base)
local offset = 0
local check = readString(readPointer(readPointer(readPointer(base)+0xC)+offset),100)
if check == nil or ((not check:find("obj_")) and (not check:find("o"))) then offset = 0x14 end
for i = 0,numObjects do
local name = readString(readPointer(readPointer(readPointer(base+i*8)+0xC)+offset),100)
if name then _G[name]=i end
end
end
function getObjectBase(objName)
if _G[objName] == nil then return nil end
local off = string.format('%X',_G[objName]*8)
local base = getAddressSafe('[[[[baseObjects]]+'..off..']+C]')
return base
end
function getObjectInstance(base,instNum)
local instMax = readInteger(base+0xD8)--You may have to change this offset depending on the game
if instNum > instMax or instNum <= 0 then return nil end
base = base+0xD0 --You may have to change this offset depending on the game
for i = 1,instNum do
base = readPointer(base)
if (not base) or base == 0 then return nil end
end
return readPointer(base+0x8)
end
When you have the object instance base, you can dive down into its properties array by (in this case) going to 0x60 and then 0x10 where all of the associated stats are (for a player or unit it would contains things like health, max health, damage, and so on).
Once you have a pointer to that array (see first picture) you can place that header under Query Object Properties to get either 'All' of the properties with their respective offsets or just a particular value (which can be helpful if you have to sift through a bunch).
Hope someone finds this interesting and helpful.
Happy Hacking,
aSwedishMagyar