Here's what I wrote tonight. It was working for me when I tested it, but I haven't done much more than grabbing the items on a particular tile. I've tried to document the code where possible to help you guys follow the logic.
Also, the item id/stack hooks are reversed.
function GetGroundItems(tile: TTile): TGroundItemArray;
var
cache, hash, plane, nodes, size, index, tail, cur, next,
uid, list, id, stack: Integer;
begin
// grab the cache and calculate the tile's hash
cache := SmartGetFieldObject(0, hook_static_GroundItemCache);
plane := SmartGetFieldInt(0, hook_static_LoadedPlane);
hash := tile.x or (tile.y shl 14) or (plane shl 28);
// grab the nodes array and get the index where our item list
// should be, if it exists
nodes := SmartGetFieldObject(cache, hook_nodecache_GetNodes);
size := SmartGetFieldArraySize(nodes, '', 1);
index := hash and (size - 1);
SmartFreeObject(cache);
// get the dummy tail node of the current list and its successor
// for use in the next loop
tail := SmartGetFieldArrayObject(nodes, '', index);
cur := SmartGetFieldObject(tail, hook_node_Next);
SmartFreeObject(nodes);
// loop until we come back to the dummy tail node
// (the list is circular)
while (not (SmartIsEqual(tail, cur))) do
begin
uid := SmartGetFieldLongL(cur, hook_node_GetID);
if (uid = hash) then
begin
// if we have matching uids, grab the list and break
list := SmartGetFieldObject(cur, hook_nodelistcache_GetNodeList);
break;
end;
// otherwise, update our node
next := SmartGetFieldObject(cur, hook_node_Next);
SmartFreeObject(cur);
cur := next;
end;
// free objects we're finished with
SmartFreeObject(cur);
SmartFreeObject(tail);
// if we didn't find our list, there are no ground items on
// this tile
if (list = 0) then
Exit;
// grab pointers for the new list
tail := SmartGetFieldObject(list, hook_nodelist_Head);
cur := SmartGetFieldObject(tail, hook_node_Next);
while (not (SmartIsEqual(tail, cur))) do
begin
// create a new ground item
SetArrayLength(Result, GetArrayLength(Result) + 1);
id := SmartGetFieldInt(cur, hook_item_GetID);
stack := SmartGetFieldInt(cur, hook_item_GetStack);
Result[High(Result)] := NewGroundItem(id, stack, tile);
// update our pointers
next := SmartGetFieldObject(cur, hook_node_Next);
SmartFreeObject(cur);
cur := next;
end;
// free remaining objects
SmartFreeObject(cur);
SmartFreeObject(tail);
SmartFreeObject(list);
end;