Reading Tibia’s Creature Structure from Memory: Battle List, Offsets, and the RL Client

The Battle List: Where Tibia Stores Its Creatures

Every creature Tibia renders near you lives in a region of the client’s memory called the battle list. It is an array of fixed-size structs — one entry per creature — each holding that creature’s ID, name, HP, max HP, and XYZ tile coordinates. Read the battle list and you know exactly what is on screen and where.

The hard part is finding it. Tibia’s RL client does not expose a documented API, so the only way in is through process memory — via ReadProcessMemory on Windows — and the offsets shift after every client update.

Step 1: Find a Creature Object with Cheat Engine

Cheat Engine is the standard starting point. Attach it to the Tibia process, find a creature on screen, and scan for its current HP as a 4-byte integer. Deal some damage, then rescan for the new value. Repeat a few times and you will narrow down to a single address — that is your landing point inside the creature’s struct.

You probably will not land on the exact start of the struct, but that does not matter. Once you have any known field inside it, offset arithmetic reaches everything else.

Step 2: Map the Structure with ReClass.NET

ReClass.NET is a free tool that reads memory around an address and lets you assign types to each byte offset, watching values update in real time as the game runs. Load your creature address as a new class and explore the surrounding bytes.

What you are looking for:

  • Creature ID — a 4-byte int, usually at or near the struct start
  • Name — a UTF-8 string or a pointer to one, typically within the first 40 bytes
  • X, Y, Z position — three 4-byte ints; Z is the floor number (0 is ground level, higher values go underground)
  • HP and max HP — a pair of 4-byte ints; easy to confirm by watching them shift as you take damage or heal

Documented offsets from Tibia 9.8 (circa 2013) placed the creature ID at +0x00, name at +0x04, Z at +0x24, Y at +0x28, X at +0x2C, and HP at +0x8C. The RL client reorganised this layout, so treat those as a directional hint rather than a working answer for the current client.

Iterating the Full Battle List

Finding one creature address only solves half the problem. To target the nearest monster or the one with the lowest HP, you need all of them.

The battle list is a flat array — structs are the same size, laid out consecutively in memory. To find the stride, put two different creatures into a Cheat Engine scan at the same time and subtract their addresses. That difference is your struct size (historically around 0xB0 bytes, though the RL client varies). Once you have the stride and a base address, walking the full list is a straightforward loop:

for addr in range(battle_list_base, battle_list_base + MAX_SLOTS * stride, stride):
    creature_id = read_int(addr + ID_OFFSET)
    if creature_id == 0:
        continue  # empty slot
    name  = read_string(addr + NAME_OFFSET)
    x     = read_int(addr + X_OFFSET)
    y     = read_int(addr + Y_OFFSET)
    z     = read_int(addr + Z_OFFSET)
    hp    = read_int(addr + HP_OFFSET)

Empty slots have an ID of zero — skip them. The maximum slot count reflects how many creatures the client can track simultaneously, which is larger than just what fits on the visible screen tiles.

Handling RL Client Updates

CipSoft pushes updates regularly, and each one recompiles the client without preserved symbol names. The battle list base address and struct offsets can both move. A bot reading correctly today may crash or return garbage after the next patch.

Two approaches survive updates more reliably than hard-coded addresses:

  • Signature (AOB) scanning — instead of storing an absolute address, you search the executable’s byte sequence for a unique pattern that appears just before or after the battle list pointer. These patterns tend to survive minor patches even when the absolute address shifts.
  • Community-maintained offset tables — several open-source projects track offsets keyed to each client version and push updates after patches. Following one of those repositories means you get corrected offsets without rescanning yourself every time.

Open-Source Projects Worth Reading

Two GitHub repositories are useful as reference code before writing anything from scratch. villor/TibiaReader is a .NET library that reads live Tibia client memory — old now, but its ReadProcessMemory wrapper and offset layout are clean and readable. Mytherin/Tibialyzer reads both memory and the server log to track damage and loot; its memory-reading section shows one practical way to handle struct changes across versions.

Neither targets current RL client offsets out of the box, but as code skeletons they save a substantial amount of groundwork.

Account Risk

CipSoft has hardened the RL client over time. External memory reads via ReadProcessMemory still work from a separate process, but the client logs anomalies and ban waves do happen. Any bot you build should be treated as fragile on two fronts: offsets break on patches, and detection risk is real. Keep that in mind before attaching anything to an account you care about.

Sources


Similar Posts