Conventions used in this document

A plain number is assumed to be in hexadecimal. A number prefixed with a plus (+) or minus (-) sign is assumed to be in decimal. A number prefixed with 0x is in hexadecimal. (This is the convention used by the SoftICE debugger.)

Conventions used in the databases

The following rules hold for most of the custom labels (that is, those that do not have one of IDA's automatic prefixes like byte_):

I'm trying to stick to TT's original conventions when naming things (vehicle, vehicle type, station etc.), as long as it's not confusing. The only consistent difference is, where TT uses the term square, I use tile (it's more specific).

Note: Just because I say object and class don't assume it has something to do with object-oriented programming (OOP). The analogy is too weak to be useful.

Classes

Both TTO and TTD code is clearly divided into several abstraction classes. Each class is identified by an integer number (the class ID), or by a corresponding class offset (more on this later). An object such as a tile or a vehicle also contains the ID of the class it belongs to; this is referred to simply as the class of the object.

There are the following classes in the TTD simulation engine:

A class offset is the class ID multiplied by 8; for instance, if the class ID of an object is 5, its class offset is 28 (hex). Class offsets are useful because some arrays (including the main array of handler tables, see below) are indexed by a class offset. The procedure GetTileTypeHeightInfo returns the class offset of a tile in the BX register.

TTO classes are slightly different:

Handlers

The main TT simulation engine communicates with subroutines belonging to various classes via handlers. A typical handler calling sequence looks like this:

  1. Registers, common data locations etc. are set up.
  2. Address of a handler table for the appropriate class offset is loaded into the EBP register from the main array of handler tables starting at ppOpClass0.
  3. The handler is called using an instruction of the form CALL [EBP+XX]. The offset XX is called the operation offset in this document.

The following table lists the operation offsets, and what I know or guess of their meaning and calling conventions. Note that entry 10 is not guaranteed to point to anything meaningful if there are no actions in a class. The table applies to TTD; TTO's handlers are similar, but so far I have not verified if their calling conventions are the same or not.

Operation offsetName (X = class ID)Meaning
Common operations
00ClassXInitHandler Initialization routines. AX = 0 when resetting the class data, AX = 1 when starting a new game or scenario.
04ClassXFunctionHandler Various class-specific functions. EBX holds the number of the function to be called, other registers are function-specific.
08TextTypeXXHandler Text handlers. EAX holds the text ID with bits +11..+15 (TTO: +10..+15) masked off, EDI points to the buffer the expanded text will be placed in. Usually, these handlers jump through TextHandler@@ProcessString to expand special codes in the string (which means they may be called recursively).
0CClassXTickProc A routine called once every simulation tick, enabled selectively for some classes (see the procedure DoAllTickProcs).
10ClassXActionHandler

Action (e.g., construction or destruction) handlers, called within DoAction. The upper word of the ESI register holds the class-specific operation number. The BL register holds action flags (also referred to as construction flags):

  • bit 0: set if the operation is to be actually done, clear if only checking
  • bit 1: if clear, conflicting landscape structures (buildings, tracks, roads etc.) are removed; if set, an error is reported (see below) if there is some landscape structure in the way
  • bit 2: (vehicle purchase actions only) if set, only the cost of the action is returned, other conditions are not checked
  • bit 3: if set, an error is reported (see below) if the operation involves building on water
  • bit 4: if set, an error is reported if the action would involve crossing or joining an existing track with a new one
  • bit 5: if set, existing houses and roads belonging to towns are removed even if bit 1 (see above) is set
  • bit 6: if set, houses may be removed even if the Local Authority rating for the company doing the action is too low

AX and CX hold the precise X and Y coordinates, respectively, of the point on the landscape (typically the north corner of a tile) where the operation is to be performed. Registers EDX, EDI and the upper 24 bits of EBX are action-specific. Also, additional action-specific parameters may be passed through the text reference stack (vaTextRefStack). wOpErrorMsg1TID contains the first part of the error message to display if the operation is not possible. bCurrentCompany is the company index (or: 10 - none, 11 - water, 80 and above - town) doing the action.

All these handlers return the cost of the operation in EBX. If the operation is not possible, EBX = 0x80000000 is returned and wOpErrorMsg2TID contains the second part of the error message to display (-1 if there's no second part). Some also return additional information in EDI.

Operations defined only for vehicle classes (10..15 for TTD, 20..26 for TTO)
14ClassXVehTickProc

This handler is invoked once every simulation tick for each vehicle (pointed to by EDI) by the procedure TickProcAllVehicles. All vehicle movement routines go there.

18ClassXMouseClickVeh

This handler is invoked when the player clicks on a vehicle on the landscape. EDI points to the vehicle.

1CVehicleClassDailyProc

This is the daily vehicle processing routine (see SimulationTick1). EDI points to the vehicle.

Operations defined only for landscape classes (0..A for TTD, 0..B for TTO)
14ClassXGroundAltCorrection

These handlers are invoked by the procedure CalcExactGroundAltitude, to adjust the ground altitude for the land classes that require it. AX and CX hold the precise X and Y coordinates, DL holds the altitude as calculated for plain ground, DH is the _landscape5 entry for the tile (accessed in DOS versions of TTD via the GS segment register), EDI bits 4, 3, 2, 1 are set if the N, E, S, W corner, respectively, is raised (other bits of EDI are zero).

Return: DL = corrected altitude, DH = 1 if the location is under a bridge, 0 otherwise. AX and CX must be kept untouched.

18ClassXClearTile

These handlers are invoked when an attempt to clear a tile is taken. AX, CX, BL are as for the operation 10 (action) handlers, DL, DH and DI are as returned by GetTileTypeHeightInfo for the tile. Return as for the operation 10.

1CClassXDrawLand

These handlers collect sprites to be displayed for a given tile. Registers as returned by GetTileTypeHeightInfo, except that BX and SI are swapped.

20ClassXPeriodicProc Called by PeriodicProc256Tiles every +256 ticks for each tile, these handlers are for things like growing of grass and trees. EBX holds the XY index of the tile.
24ClassXRouteMapHandler These handlers are called to determine in which directions a vehicle can travel on a tile. EDI holds the tile's XY index, AX = 0, 2 or 4 to get railway, road and water routes, respectively. Return a map of routes in EAX.
28ClassXVehEnterLeave These handlers are called when a vehicle tries to move on a tile (DL=0), or leaves a tile (DL=1). EDI points to the vehicle, EBX holds the XY index of the tile. Return updated (if necessary) XY index in BX, plus some flags in the upper word of EBX (bit 31 set = movement not possible).
2CClassXMouseClick These handlers are called every time the player clicks on a tile with the normal (arrow) cursor. EDI holds the XY index of the tile, AL and CL hold the precise X and Y coordinates wihtin the tile, DL and DH are as returned by GetTileTypeHeightInfo for the tile. Return AL = 0 if nothing happened, 1 if something has been activated.
30ClassXAnimationHandler These handlers are called every tick for animated tiles (see AnimateTileObjects). EBX holds the XY index of the tile to be animated.
34ClassXQueryHandler

This operation is invoked to query a tile. EDI holds the XY index of the tile.

  • If AL=0 on input, return three types of accepted cargo in AL, BL and CL, and the respective amounts of acceptance (in 1/8 units) in AH, BH and CH.
  • If AL=1 on input, set AL=FF if the tile belongs to a cargo-producing industry, and return two types of generated cargo in BL and BH.
  • If AL=2 on input, return a text description in AX (text ID) and ECX (reference stack), and the owner in BL.
38ClassXSellHandler This operation is invoked for all tiles when a company goes bankrupt or is taken over, to change the ownership of tiles owned by it. EBX holds the XY index of the tile being sold, DL = ID of the original company, DH = ID of the company that takes it over or FF if the original company is being just sold off.