The .frt format is a binary file format used in GZ and TPP to store an AI route set. A route set contains a number of routes, which dictate AI movement and behavior.
There is a file format implementation in FoxLib.
frt files can be opened and created with FoxKit. Further info here.
Each quest and each mission can load a single frt file at a time. Some missions have more than one frt, but in different fpks, so only one of them is loaded at a time. A given AI agent is assigned a number of routes, and which one it’s currently using is dependent upon the alert state:
You can change an agent’s sneak route in Lua by calling:
GameObject.SendCommand(gameObjectId, { id="SetSneakRoute", route=routeId })
where gameObjectId is the GameObject’s ID (obtained through calling GameObject.GetGameObjectId) and routeId is the name of the desired route, for instance, rts_ptr_e_citadel_W_0000. The caution and alert routes can be changed the same way, using “SetCautionRoute” and “SetAlertRoute” respectively.
For a detailed description of the route system, see the article on routes.
There are two known frt formats: one used in GZ and one used in TPP. The GZ format uses a packed World Space Vector3 in a uint64 with an origin point in the header.
If version is GZ:
If end.
If version is GZ:
If end.
The header is followed by the route IDs, of which there is one for each route. A route ID is a StrCode32 hash, and is the name the route is referred to by in Lua or route event parameters.
After the route IDs are the route definitions, of which there is one for each route. The offsets listed in each entry are relative to the entry’s own offset. In other words, add the offset for the route definition to its component offsets in order to find the data that they point to.
This section contains the node positions in sequential order. The first route’s node positions are stored here, then the second route’s node positions, and so on. The GZ version packs its node positions into uint64.
If version is GZ:
The first 21 bits are the x coordinate, with the most significant bit, 21, serving as the sign. The same follows for the next 19 bits for for the y coordinate and the rest of the 21 bits for the z coordinate. Finally, each are divided by 1024, and added onto the origin point Vector3 world position.
If version is TPP:
This section contains metadata for each node linking it to its events. There is one entry for each node.
Contrary to what you might expect, the edge event index is an index into the route’s event list, not the routeset’s. In other words, it will always be 0 for the first node in a route, and will increment for each subsequent node by its event count.
This section contains all of the events in sequential order. The first node’s events are stored here, then the second node’s events, and so on. The first event in each node’s event list is its edge event.
If version is GZ:
If end.
If version is TPP:
If end.
One of the following Aim Point Param sets will be used based on the Aim Point Enum.
All params are zero. The route agent has no aim target.
The route agent uses a world space point as an aim target.
The route agent uses a character id as an aim target. Examples of the strings hashed here include “Player” for the player, and GameObjectLocator entity names, like “SupportHeli” or “hos_quest_0000”.
The route agent uses a special route as an aim target. If the hash is of an empty string, “”, it will be skipped.
Very rare, and seems to be structurally identical to Route as Sight Move Path (3). Not much is known about it.
One of the following Event Type Param sets will be used based on the Event Type hash.
Here are some of the discovered event types and their known parameters:
Used by VehicleBackFast, VehicleBackNormal, VehicleBackSlow, VehicleMoveFast, VehicleMoveNormal, VehicleMoveSlow and VehicleDir in TPP.
Used by RelaxedIdleAct and CautionIdleAct in TPP.
Used in GZ.
Used in TPP.
Used by SendMessage, and strangely by PutHostageInVehicle and TakeHostageOutOfVehicle, in TPP.
Used in TPP. If a route agent triggers this event, a designated Lua function will be called with the “function name” and “argument” hashes, and if it returns true, the route agent will change to the specified route. This function can be found in TppEnemy.lua.
The game’s default vanilla functions only include “IsGimmickBroken”, “IsNotGimmickBroken”, “CanUseSearchLight” and “CanNotUseSearchLight”. If the function name is not one of these four, this function will return true.
“IsGimmickBroken” checks if the argument hash is a broken gimmick with TppGimmick.IsBroken, and returns true if so, allowing the route agent to switch routes. Naturally, “IsNotGimmickBroken” simply returns the opposite. “CanUseSearchLight” similarly checks if the gimmick in the argument is not broken, and if it’s currently nighttime with TppClock.GetTimeOfDay, returning true only if both are correct. “CanNotUseSearchLight” also returns the opposite here.
Used in TPP.
Used in conjunction with the mission’s syncRouteTable.