The FloorData is the key part of the level structure, which defines almost everything related to physical'' world — geometry, interaction and response of
a level. While room geometry (see above) may be considered as a
face'' of the level, FloorData is its heart'' and
brain''.
Distinctive feature of the FloorData is its serialized nature. While in room geometry you can easily jump through structures using data sizes and pointers to get the needed part, FloorData require sequential parsing, one unit by one.
The FloorData defines special sector attributes such as individual floor and ceiling corner heights (slopes), collisional portals to other rooms,
climbability of walls, and, most important of all, the various types of triggering. Each room sector (see [tr_room_sector] structure) points to the
FloorData using FDIndex
variable. It is referenced as an array of 16-bit unsigned integers (uint16s).
Therefore, the current [tr_room_sector] offset (not yet the FloorData pointer itself!) is calculated using this formula:
\(S_{Offset} = (((X_{current} - X_{room}) / 1024) \times n_{Zsectors}) + ((Z_{current} - Z_{room}) / 1024)\) |
…where \(X_{current}\) and \(Z_{current}\) are current player positions, \(X_{room}\) and \(Z_{room}\) are corresponding tr_room_info.x and tr_room_info.z fields, and \(n_{Zsectors}\) is tr_room.NumZsectors value.
Then, the current FloorData pointer is derived from calculated [tr_room_sector] structure’s FDIndex
field. In other words, FDindex
is an offset into the
FloorData[]
array.
As mentioned above, The FloorData consists of solely uint16_t
entries without general structure — the way engine treats specific entry depends on the
sequence order and type of previously parsed entries. While it’s a bit difficult to understand it at first, you should get used to it. Main thing to remember is
the FloorData should be read sequentially.
First order of FloorData entries has a common `bitwise'' structure, which we will call `FDSetup
. The structure could be divided into three fields:
|
bits 0..4 ( |
|
bits 8..14 ( |
|
bit 15 ( |
Function
defines the type of action that must be done with current FloorData entry, and SubFunction
is usually used in that action’s conditions and case
switches (if there are any). If there are no any special conditions for a given Function
, then SubFunction
is not used.
Tip
|
It may seem that bits 5..7 are unused in FDSetup structure, but actually they belong to Function value, but only in TR1 and TR2. When parsing FDSetup for TR3+, you should use only the lower 5 bits (0..4) to find the Function value, because some of TR3 triangulation functions use the upper
3 bits of the lower byte for other purpose. However, this will also work correctly in TR1 and TR2, since maximum possible function value is way below 5-bit limitation.
|
If EndData
is set, there should be no more similar FloorData entries (after the current one) in the FloorData[]
array — so further parsing must be
stopped. Otherwise, the following uint16_t
should be interpreted after the current one in the same manner.
Note
|
Even if EndData is set, it doesn’t specifically mean that there are no more uint16_t following the current one at all. As we will see, some FloorData
functions and subfunctions require to parse additional entries with their own rules. In programming terms, EndData just indicates that parsing loop must be
broken — however, there may be following code which reads additional entries.
|
Note
|
While FloorData index 0 means the sector does not use floordata, there is still a ``dummy'' entry for index 0. This dummy entry doesn’t contain any
useful information.
|
Note
|
Several of the functions indicate adjustments to the sector’s corner heights. The corners will be denoted as 00 , 01 , 10 , and 11 , where the first
digit is the corner’s X coordinate and the second digit is the corner’s Z coordinate, with both given as multiples of 1024.
|
Note
|
Collisional floordata functions should always come first in sequence, with floor collision function strictly being first and ceiling collision function strictly being second. The reason is hardcoded floordata collision parser which always expects these two functions to be first in sequence. |
SubFunction is not used
The next FloorData
entry is the number of the room that this sector is a collisional portal to. An entity that arrives in a sector with this function
present will gets its room membership changed to provided room number, without any change in position.
To understand what exactly happens when room membership is changed, you must understand how collisional portals work in Tomb Raider’s 4D space. When two rooms are connected with portal, it means that they also overlap within a distance of two sectors (because these sectors contain portal in each of the connected rooms). This way, when room is changed, it remains unnoticed by the player, cause portal sectors are interconnected:
Collisional portal layout. Blue sectors are walls around each room. Green sector is Room 2’s collisional portal to Room 1, and dark blue sector is Room 1’s collisional portal to Room 2 |
SubFunction is not used
The next FloorData
entry contains two uint8_t
slant values for the floor of this sector. Slant values are specified in increments of 256 units
(so-called clicks in TRLE terms). The high byte is the Z slope, while the low byte is the X slope. If the X slope is greater than zero, then its value is
added to the floor heights of corners 00
and 01
. If it is less than zero, then its value is subtracted from the floor heights of corners 10
and 11
. If
the Z slope is greater than zero, then its value is added to the floor heights of corners 00
and 10
. If it is less than zero, then its value is subtracted
from the floor heights of corners 01
and 11
.
Note
|
This function is never combined with triangulation functions present in TR3 onwards (see further). |
SubFunction is not used
The next FloorData
entry contains two uint8_t
slant values for the ceiling of this sector. Slant values are specified in increments of 256 units. The
high byte is the Z slope, while the low byte is the X slope. If the X slope is greater than zero, then its value is subtracted from the ceiling heights of
corners 10
and 11
. If it is less than zero, then its value is added to the ceiling heights of corners 00
and 01
. If the Z slope is greater than zero,
then its value is subtracted from the ceiling heights of corners 00
and 10
. If it is less than zero, then its value is added to the ceiling heights of
corners 01
and 11
.
Note
|
This function is never combined with triangulation functions present in TR3 onwards (see further). |
The uint16_t
immediately following current entry is called TriggerSetup
, and contains general trigger properties stored in a ``bitwise'' manner:
|
bits 0..7 ( |
|
bit 8 ( |
|
bits 9..13 ( |
Timer
is a value generally used for making timed triggers of certain entities — for example, the door which opens only for a few seconds and then closes,
or a fire which extinguishes and then burns again. In such case, engine copies timer value in corresponding field of each triggered entity. Then each entity’s
timer begins to count time back, and when it reaches zero, entity deactivates.
However, it’s not the only purpose of Timer
field. As trigger may not specifically activate entities but do some other actions, Timer
field may be re-used
as a general-purpose numerical field to specify particular trigger behaviour. We will mention it separately for such trigger actions.
Note
|
Since TR4, Timer field became signed, i.e. it may contain negative values. Effectively, it means that entities activated with such trigger won’t be
immediately activated and then deactivated after given amount of time, but wait for a given time before being activated. Most prominent example is timed spike
pit in the beginning of ``Burial Chambers''.
|
Mask
: The five bits at 0x3E00
are the so-called Trigger Mask. The purpose of trigger mask is to create puzzle set-ups which require a combination of
activated triggers to achieve certain result. A good example of trigger mask use is the multiple-switch room of ``Palace Midas'' in TR1.
Note
|
Each entity in Tomb Raider has a similar field in its structure called activation mask. Activation of entity happens only when all bits of activation mask
are set. Trigger action which activates an entity makes either bitwise Whenever entity’s activation mask is changed to anything but 0x1F (all bits set), entity is automatically deactivated, excluding the cases when |
OneShot
flag is used only for activation of entities (it is also copied to entity’s own flag field with same name), and indicates that after activation,
entity state is locked. It means that even if entity’s own activation mask is unset (as with switch trigger type — see further), entity will remain
activated. However, it doesn’t mean that entity couldn’t be deactivated at all — because antitrigger trigger type (see further) ignores and resets this flag.
{TR1}{TR2} In these versions, any antitriggers for locked entity have no effect, and engine completely bypasses antitrigger processing for such entities. It means that once entity was activated by trigger with OneShot
flag, it couldn’t be deactivated at all.
{TR3} There’s a bit different OneShot
flag behaviour for TR3 — entity state will be locked even if activation mask isn’t set yet. For example, if there are two complementary triggers for certain entity (let’s say, with activation masks 0x0F
and 0x10
), and each of them has OneShot
flag, effectively target entity won’t ever be activated, cause each trigger immediately locks entity state, bypassing further trigger processing.
Note
|
All other trigger actions, except activation of entities, are performed continuously. It’s not obvious, because engine uses various workarounds for specific trigger actions to prevent ``repeated'' execution, like playing same soundtracks over and over again. Such workarounds will be specifically mentioned. |
Trigger types and trigger actions will be described separately right after listing all FloorData functions.
SubFunction not used
Instantly kills Lara. Usually she is simply set on fire, however, there is one special case in TR3. If current level index is 7 (``Madubu Gorge''), then instead of catching fire, Lara will play drowning animation.
{TR2}{TR3}{TR4}{TR5} The SubFunction
indicates climbability of walls; its value is the bitwise OR
of the values associated with all the climbable-wall
directions (0x01
= +Z, 0x02
= +X, 0x04
= -Z, 0x08
= -X), e.g. SubFunction 0x09
indicates that the walls on both the +Z and -X sides of this sector are
climbable.
{TR3}{TR4}{TR5} Beginning with TR3, geometry layout of each sector was significantly changed. Engine introduced triangles as a minimal collisional unit, compared with rectangles only in TR1 and TR2. This advantage allowed to create much more organic and natural terrain (albeit still limited by minimal sector width and depth of 1024 units), but also complicated things a lot, introducing the whole new set of different FloorData collisional functions.
Note
|
Triangulation functions are never combined with slant functions present in TR1 and TR2. Each sector has either slant or triangulation function assigned to it, and never both of them. If there ever will be a paradoxical case of combination, most likely, only older function (i.e. slant) will be considered for collision calculation. |
Similarly to slant functions, triangulation functions define the floor and ceiling corner heights, but besides, they also specify dividing up the floors and ceilings into triangles along either of the two diagonals. Also, one of the triangles may be a collisional portal to the room above (if in the ceiling) or to the room below (if in the floor).
Each triangulation function uint16_t
must be parsed differently, not like ordinary FDSetup
entry:
Function |
Bits 0..4 ( |
\(H_{\triangle1}\) |
Bits 5..9 ( |
\(H_{\triangle2}\) |
Bits 10..14 ( |
EndData |
Bit 15 ( |
\(H_{\triangle1}\) and \(H_{\triangle2}\) are signed values, and replace FDSetup’s `SubFunction
field.
Own triangulation function’s uint16_t
is followed by one extra uint16_t
to be parsed as follows:
\(\DeltaC_{10}\) |
Bits 0..3 ( |
\(\DeltaC_{00}\) |
Bits 4..7 ( |
\(\DeltaC_{01}\) |
Bits 8..11 ( |
\(\DeltaC_{11}\) |
Bits 12..15 ( |
All four values here are unsigned.
The idea behind this set up is dividing each sector rectangle into two independent triangles, and adjust each triangle height by combination of corner and triangle heights. To get each triangle’s individual corner height, you should use this formula:
\(H_{\angle} = H_{floor} + (\max(\DeltaC_{10}, \DeltaC_{00}, \DeltaC_{01}, \DeltaC_{11}) - \DeltaC_{n} \times 1024 )\) |
…where \(H_{\angle}\) is absolute floor height specified in [tr_room_sector]'s Floor
field, and \(\DeltaC_{n}\) is triangle’s
individual corner height.
While four corner height values are shared by both triangles, triangle height values specify additional overall height of individual triangle. Therefore, sector corner heights may or may not be shared between two triangles:
Corner heights are not shared |
Corner heights are shared |
The way engine interprets triangle height values \(H_{\triangle1}\) and \(H_{\triangle2}\) is not exactly known — however, meta2tr understands them and uses them to create so-called diagonal steps, example of which is pictured on the left side. There is no case of diagonal steps in original games, but they may exist in levels edited with meta2tr.
Overall, there are 12 different triangulation functions, which can be divided into two pairs of groups — one pair of groups is for floor, and another pair is
for ceiling. Each pair is categorized by split direction, and each group is categorized if it’s floor or ceiling. In each group, there are three functions — first function denotes that both triangles in sector are solid, second and third functions denote that one of triangles is a collisional vertical portal.
When function denotes a vertical portal, target room of a portal is taken from [tr_room_sector] structure — RoomBelow
for floor functions, and RoomAbove
for ceiling functions.
Here is an example illustration depicting sectors with all possible floor triangulation functions. Ceiling triangulation happens in similar manner.
Floor sector triangulation types. Black triangles depict vertical collisional portal to different room. |
X
axis in world coordinates also may be considered north for more simple reference (because you can always check compass direction in actual game engines,
at least in TR1 and TR4).
These functions define floor triangles split in the northwest-southeast direction.
-
0x07
— Both triangles are solid. -
0x0B
— Triangle pointing its right angle to the southwest is a collisional portal. -
0x0C
— Triangle pointing its right angle to the northeast is a collisional portal.
These functions define floor triangles split in the northeast-southwest direction.
-
0x08
— Both triangles are solid. -
0x0D
— Triangle pointing its right angle to the southwest is a collisional portal. -
0x0E
— Triangle pointing its right angle to the northwest is a collisional portal.
These functions define ceiling triangles split in the northwest direction.
-
0x09
— Both triangles are solid. -
0x0F
— Triangle pointing its right angle to the southwest is a collisional portal. -
0x10
— Triangle pointing its right angle to the northeast is a collisional portal.
These functions define ceiling triangles split in the northeast direction.
-
0x0A
— Both triangles are solid. -
0x11
— Triangle pointing its right angle to the northwest is a collisional portal. -
0x12
— Triangle pointing its right angle to the southeast is a collisional portal.
SubFunction is not used
{TR3}{TR4}{TR5} Sets monkey-swingability of the ceiling in specified sector.
{TR3}{TR4}{TR5} This function has a different meaning in TR3 and TR4/5.
-
In TR3, if Lara approaches sector with this FloorData function inside minecart vehicle, it will turn left 90 degrees, with a circle radius around 4 sectors (4096 units in world coordinates). If both this and
0x15
functions are set for a given sector, minecart will stop there. -
In TR4 and TR5, this function is used together with special entity called Trigger Triggerer. The purpose of this entity is to perform deferred triggering. That is, if trigger FloorData function is placed in the same sector with function
0x14
, trigger won’t be activated until there’s an activated Trigger Triggerer object in the same sector. This allows to create setups where player can cross trigger sector without activating it, until some other event occurs later in level.
{TR3}{TR4} This function has a different meaning in TR3 and TR4.
-
In TR3, if Lara approaches sector with this FloorData function inside minecart vehicle, it will turn right 90 degrees, with a circle radius around 4 sectors (4096 units in world coordinates). If both this and
0x14
functions are set for a given sector, minecart will stop there. -
In TR4, this function is used together with special entity called Mapper. If Mechanical Beetle is placed in sector with function
0x15
and inactive Mapper entity, it rotates in the same direction Mapper is pointing to, activates it, and then rolls forward, until next sector with function0x15
is reached. Then it waits until Lara picks it up.
Note
|
If Lara places beetle at the very same sector where beetle was already used, it will shake and explode. It happens because beetle checks if Mapper entity is active or not, and if it was already activated, it explodes instead of rolling. |
A trigger type specifies the condition of a given trigger function to be activated. Condition may be a type of activator (Lara or some other entity), a specific state of activator, specific trigger action (activate or deactivate), and so on.
Trigger type is placed in SubFunction
field of FDSetup
structure, so we will refer to trigger types as SubFunctions.
Note
|
Trigger type names are directly borrowed from TRLE. |
Activated by Lara whenever she enters a given sector — either steps, climbs, jumps over it, and so on.
This particular type of trigger takes first ActionList
entry’s Parameter
field as a reference to specific switch entity in level. It activates every time
the switch state is changed. For Object trigger actions, activation means performing XOR
operation on these object’s (entities) activation masks. (See
next section for description of Object trigger action and Parameter
field.)
Please note that this trigger type (as well as any other trigger types) always perform all trigger actions except Object in the same manner! Meaning, if there is a Camera or Flipeffect trigger action, it will be performed every time the switch is flipped on or off.
Similar to previous trigger type, it works only if there is a keyhole entity listed in the first ActionList
entry’s Parameter
field. It activates only if
a key was inserted into that particular keyhole.
As above, this type of trigger works only if there is a pick-up entity listed in the first ActionList
entry’s Parameter
field. It activates only if this
item was picked up by Lara.
Activated by specific entity type (activator) wherever it enters a specified sector. Entity types which are able to activate heavytriggers are hardcoded, and usually include NPCs (enemies), rolling balls and pushable objects. Since TR4, heavytriggers may also be activated by destroying shatter static mesh which is placed in a given sector.
Note that heavytrigger does not perform deactivation action, if activator leaves trigger sector.
Same as Pad — activates only if Lara has landed or stepped onto a given sector. The difference is, Antipad performs deactivation for each case of Object trigger action. What deactivation specifically means is it resets entity activation mask to zero (trigger mask is ignored), thus flipping entity activation procedure.
As it was mentioned for Switch trigger type, any other trigger actions beside Object will perform exactly in the same manner as with normal trigger types. So you shouldn’t expect soundtrack to stop, if you have placed PlayTrack trigger action for antipad.
Activated by Lara whenever she enters a given sector with her weapons drawn. This trigger type was (presumably) never used in original games.
This type doesn’t perform any trigger action listed for it except Object type — for these trigger actions, it applies standable collision for Lara on a given entities, if such entities are in this trigger sector. For particular entity types, it works even if entity is deactivated (e.g. collapsing floor), but for other types it works only if entity was activated (e.g. trapdoors). Selected behaviour is most likely hardcoded.
It’s worth noting that any trigger type will apply standable collision on such entity types, if they are in the same sector. It’s not a bug, rather a way TR engines process FloorData.
Same as Trigger, but performs deactivation for each case of Object trigger action.
{TR3}{TR4}{TR5} Antitrigger type also copies its parent trigger’s OneShot
flag into any entities activated by Object trigger action, meaning that after any further entity activation it will be locked.
{TR4}{TR5} Don’t be fooled by the name of this trigger type. It is not literally a switch, as only similarity between it and switch type is XOR operation with activation mask. In fact, this trigger performs action when specific entity type (activator) enters a given trigger sector, but only if trigger mask is equal to activator’s activation mask.
The best example of heavy switch setup is Planetarium in ``The Lost Library''. Trigger mask is only applied to raising block if pushable in trigger sector has a similar activation mask.
{TR4}{TR5} Same as Antitrigger, but performs deactivation for each case of Object trigger action.
{TR4}{TR5} Activated by Lara whenever she enters a given sector in monkeyswing state. Best example is locust swarm attacking Lara when she monkeyswings across the street in ``Trenches''.
{TR5} This trigger type temporarily replaces Lara model with a combination of models #25 (Lara skeleton), #26 (see-through body) and #27 (see-through joints). See-through body and joints are applied on top of the skeleton model with additive blending.
{TR5} Activated by Lara whenever she enters a given sector walking on a tightrope.
{TR5} Activated by Lara whenever she enters a given sector crawling or crouching.
Trigger function references an additional list of FloorData entries called ActionList
, which is a `chain'' of entries that immediately follows `TriggerSetup
entry. As you maybe already guessed, the ActionList
contains the list of actions to be performed for a specified trigger.
ActionList
entry format is:
|
bits 0..9 ( |
|
bits 10..14 ( |
|
bit 15 ( |
TrigAction
is a type of action to be performed. These will be listed seperately.
Parameter
is used with certain trigger actions which need a certain numerical argument provided to them.
ContBit
flag meaning is similar to EndData
flag described for FDSetup
structure. It indicates if there is another ActionList
entry after current one. If
ContBit
is not set, it means we have reached the end of ActionList
, and there’s nothing more to do for a given trigger.
Note
|
If ActionList’s parent trigger type is either Switch or Key, first entry of `ActionList is used to get reference entity (switch or keyhole) index.
Hence, it is ignored here, as by the time engine reaches ActionList offset, its first entry is already parsed by preceding code.
|
Note
|
ContBit flag is not the same as EndData flag! When writing a parser, do not overwrite one with another.
|
Switches to camera. Parameter
(bits 0..6 used) serves as index into Cameras[]
array.
Note
|
Camera trigger action uses one extra uint16_t entry after its own entry! Its format is: |
|
bits 0..7 ( |
|
bit 8 ( |
|
bits 9..13 ( |
|
bit 15 ( |
Timer
is a number of seconds to wait before automatically switching back to the normal camera. If 0, it never switches back to normal camera, as long as
trigger is active.
Once
: If set, only switch to camera once; otherwise, switch to camera every time trigger is active.
{TR1}{TR2}`MoveTimer`: Specifies time which is used to smoothly move camera from Lara to desired camera viewpoint. Movement is done via spline function. The larger value is, the more time it takes to move camera away from Lara. Therefore, if MoveTimer
is zero, then camera immediately cuts to new viewpoint.
Note
|
ContBit flag overwrites the same flag from the preceding ActionList entry.
|
Continuously moves Lara to specifed sink. Parameter
serves as index into Cameras[]
array. If sink is placed lower than current sector absolute floor
height or upper than current sector absolute ceiling height, \(Y\) coordinate will be ignored when dragging Lara to sink. Since TR3, sink also
prevents Lara from surfacing the water.
Note
|
While it may look like Cameras[] array was mentioned here by mistake, it is not. TR engines share the same structure for both cameras and sinks. The
way engine treats it in either case will be discussed in corresponding section.
|
FlipMap is an internal engine array of uint8_ts which is used to determine if alternate rooms should be turned on or off (in TRLE terms, flipped). It uses
trigger mask in the same manner as for Object activation and deactivation, but in this case, alternate rooms are activated if given FlipMap
entry mask is
set (0x1F
), and deactivated, if FlipMap
entry is not set (not 0x1F
).
This trigger action at first applies trigger mask to a given FlipMap
entry using OR
bitwise operation and then immediately checks if it’s already set or
not. If FlipMap entry is set, then it immediately switches rooms to alternate mode.
Parameter
defines which FlipMap
entry engine should refer to decide should it switch alternate rooms on or off. The size of FlipMap
array is around 10
(judging by the number of unused FLIP_MAPn
flipeffect entries), but in original levels, number usually never tops 2 or 3.
Note
|
From TR1 to TR3, FlipMap array was merely used as a hint table'' to tell the engine if it should flip all rooms at once. That is, to check and apply
another FlipMap entry, alternate rooms should have been reverted to previous state before — that’s the purpose of next two listed trigger actions. However, in
TR4 algorithm was changed — each flippable'' room now bears additional parameter called `alternate group'', which strictly tells an engine to flip it only
when room alternate group is equal to FlipMap `Parameter value. This change in algorithm made next two trigger actions unnecessary in TR4-5 (however, they are
still available).
|
Tries to turn alternate rooms on, judging on current value of a given FlipMap
entry (entry index is specified by Parameter
). If corresponding FlipMap is
not set (i.e. the value is not 0x1F
), rooms won’t be flipped. Parameter
defines a FlipMap
entry to work with.
Tries to turn alternate rooms off, judging on current value of a given FlipMap
entry (entry index is specified by Parameter
). If corresponding FlipMap is
not set (i.e. the value is not 0x1F
), rooms won’t be flipped. Parameter
defines a FlipMap
entry to work with.
Specifies an entity which current camera should look at. If current camera is ordinary'' one following Lara, then it will also rotate Lara model in a target
direction, creating an illusion of Lara looking at it. If current camera is changed to
triggered'' one (by trigger action 0x01
— see above), then this
camera’s orientation will be changed to a given entity. Note that if such camera change is desired, this action should come first, not the Camera one.
Parameter
specifies an entity index to look at.
Immediately loads next level. In TR1-3 and TR5, Parameter
field is not used, i.e. engine just loads next level specified in script.
{TR4} In TR4, so called `hub system'' was implemented, which allows Lara to jump between levels back and forth. For this reason, `Parameter
field must also explicitly specify level index to jump.
{TR4}{TR5} Also, since TR4 Lara can have multiple start positions for each level, so Timer
field in TriggerSetup
entry specifies an index of lara start posision AI object in AI objects array to warp Lara to. That is, if there’s an end level trigger with value 3
in Timer
field, it means that Lara will be warped to third start position AI object in AI objects array. For more info on AI objects, refer to this section.
Triggers a playback of a soundtrack specified in Parameter
field. Type of soundtrack (looped or one-shot) is hardcoded and assigned automatically.
This trigger action makes use of trigger mask and one-shot trigger flag to mark if this track was already played with a given trigger mask or not in a
special internal soundtrack map. That is, if it is called with trigger mask set to, say, 0x01
, then all further calls from triggers with same trigger
mask will be ignored. However, if same track playback is called with trigger mask value of 0x02
, it will play again, as it’s another byte in trigger
mask. Effectively, it allows to play specified track six times (five bits of activation mask plus one bit of one-shot flag). Comparison is done via
bitwise AND
operation, so if playback is called with trigger mask + one-shot value of (0x1F + 0x20 = 0x3F)
, then any other playback call to that track
will be blocked.
Note
|
In TR1, soundtrack playback is more complicated. For some reason, in PC version programmers completely disabled playback for majority of soundtracks, leaving only five or six most significant ones to play (like title theme or cutscene audio). Looped soundtracks were also completely ignored — instead, background ambience is explicitly specified by script entry, rather than trigger action (that’s the reason why PC version has four different ambience types when compared to PSX version). To overcome this issue and enable complete soundtrack functionality, several patches were created by the community. However, PC version is missing soundtrack map structure, which potentially produces bugs when single track could be played independently by both triggers in the same level, although mostly this bug comes unnoticed, as majority of TR1 soundtracks are engaged only once in a level. |
By the name of flipeffect'' comes any non-trivial or special trigger action which should be
seperately defined. This workaround was implemented because TR engines lack any scripting language to program arbitrary trigger, so you can consider a flipeffect as a call to some
pre-compiled'' scripted function.
Note
|
Flipeffect does not mean flip map effect'' or so, and has no any direct relation to flip maps''.
|
For example, in TR2 ``Lara’s Home'', there is a need to control assault course timer, like restarting it while reaching start point or stopping it when Lara is off the course. This task is accomplished via several different flipeffects.
Note
|
The list of flipeffects differs across game versions. For precise info on each flipeffect for each game version, refer to this section. |
Plays `secret'' soundtrack theme and marks a secret number specified in `Parameter
field as found. For finding each secret, another Parameter
value must be
specified, or else secret won’t be counted as found.
{TR1}{TR2}{TR3} Removes dead bodies of enemies from a level to conserve memory usage. This action has effect only on entities which had clear body flag
specified in their parameters (see further). Parameter
field is unused.
Note
|
This trigger action caused significant confusion in TRLE community. In level editor, action is called BODYBAG, and makes no visible effect in game, so
various speculations were made regarding action’s true purpose. Some people thought it is used to attach a backpack to Lara in Angkor Wat'' cutscene, another
people thought it is used for lipsync or dragging SAS troop body in City of the Dead''. All this speculation was proven wrong.
|
{TR4}{TR5} Engages a flyby camera sequence specified in Parameter
field. The feature was added in TR4 and enables to play cinematographic interludes with
camera continuously ``flying'' from one point to another. Such sequences, their points, properties and order are defined in a level editor, and engine moves
camera across them using spline function.
uint16_t immediately following flyby’s own entry contains one-shot flag at 0x0100
. If this flag is not set, flyby will infinitely loop. As with Camera TrigAction, flag at 0x8000
is a continuation bit, which overrides previous entry’s continuation bit.
{TR4}{TR5} Engages a cutscene pre-defined in script file. Parameter
is taken as cutscene ID. In turn, script file refers to CUTSEQ.PAK
(TR4) or CUTSEQ.BIN
(TR5) file to get all the data for a cutscene, such as actor positions and animations, camera movement, soundtrack and many more. There will be a special
section describing particular CUTSEQ.PAK
file format.
This concludes the description of Trigger FloorData function action types.