-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathtrosettastone-orig.htm
2925 lines (2864 loc) · 172 KB
/
trosettastone-orig.htm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Mozilla/4.6 [en] (Win98; I) [Netscape]">
<title>Tomb Raider II Data Formats</title>
</head>
<body link="#0000FF" vlink="#800080">
<center><b><i><u><font size="+3">TRosettaStone</font></u></i></b>
<p><b>Tomb Raider II .TR2 Data File Format</b>
<br><font size="-1">(Including Tomb Raider .PHD/.TUB and Tomb Raider III .TR2 information, where available)</font>
<br><font size="-1">(Also includes TOMBPC.DAT script information)</font>
<br><font size="-2">Document Version 1.00 (991108)</font>
</p><p><i><font size="-2">The Rosetta Stone was the key that unlocked the mysteries
of Egyptian hieroglyphics. It contains an inscription praising King Ptolemy
V, which is repeated three times - once in hieroglyphic, once in demotic,
and once in Greek. By translating the Greek, comparisons could be made
with the demotic and hieroglyphic versions, providing an invaluable lexicon
with which to translate other hieroglyphic works. The efforts that went
into making the document you are now reading could be likened to a form
of digital archæology, and hopefully this document will provide sufficient
information for others to decipher and create their own "TR-hieroglyphic"
works.</font></i></p></center>
<p> This document contains detailed descriptions of the
Tomb Raider II data file formats ({Level-name}.TR2 and TOMBPC.DAT). It
is assumed that the reader has knowledge and experience programming in
C or C++, and has at least a passing familiarity with graphics programming.
This document is self-contained; all hyperlinks refer only to itself. All
information in this document was derived independently, without the aid
or assistance of anyone at Core Design or Eidos. As such, the information
in this document may contain errors or omissions, and all structure and
variable names were deduced from the interpretation of the data (and therefore
could be misleading or completely wrong). All the information in this document
was tested and is therefore plausible, but could also be a misinterpretation.
All information herein is provided as is - you get what you pay for, and
this one's free. This was a spare-time project that set out to document
the Tomb Raider 2 file format; along the way, additional information about
Tomb Raider 1 / Gold (.PHD, .TUB) and Tomb Raider 3 (.TR2) files became
available, and that information is provided in context. Where applicable,
Tomb Raider I, Tomb Raider Unfinished Business, and Tomb Raider Gold are
all referred to as TR1, and if the information specific to TR1 is interspersed
with TR2 information, the <font color="#FF0000">TR1 information is highlighted
in RED</font>. Likewise, Tomb Raider III is referred to as TR3, and <font color="#008000">information
specific to TR3 is highlighted in GREEN</font>. In the few places
where there is such information, <font color="#000080">information specific
to TR2 ONLY is highlighted in BLUE</font>. Everything else is assumed
to pertain to TR2 only, or to all three games. [Late note: as this document
was being prepared for release, the Tomb Raider: Last Revelation demo was
released. .TR4 files will be hopefully be addressed in a future revision
of this document.]
</p><p> Because of Core/Eidos' position on Tomb Raider level
editing tools, it is suggested that any tools that you develop be released
in source code form, anonymously, using Usenet newsgroups. Anonymity
can protect you from legal action, wide distribution via Usenet prevents
Core/Eidos from attempting to recall or control the distribution of your
software, and distributing source code both allows multi-platform development
(e.g. let others port it to the Mac or Linux for you) and encourages others
to write utilities, since they can learn and benefit from your source code.
Also, Linux has taught us that 40,000 people debugging a single application
makes for a clean final product ;-)
</p><p>Tomb Raider, Tomb Raider Gold, Unfinished Business, Tomb Raider II,
Tomb Raider III, Lara Croft, and all images and data within the data files
and game engine are Copyright © Core Design and/or Eidos PLC.
Modification and/or distribution of any part of a Tomb Raider data file
(any version) is almost certainly a copyright violation.
</p><p>This document was composed at a screen resolution of 1024x768, and is
best viewed at that resolution. It contains many links, but all of
them refer only to this document; no link from this page will take
you to another web site, and this document can be viewed offline (not connected
to the Internet). Use your browser's <b>BACK</b> button to return
from a link, e.g. if you click on a structure declaration to see its definition,
clicking <b>BACK</b> will return you to your point of origin after you've
examined the structure definition.
</p><p>
</p><hr>
<center>
<p><b><u><font size="+2">Table of Contents</font></u></b></p></center>
<p> <a href="#Fundamentals">I. The Fundamentals</a>
<br> <a href="#Fundamentals_Overview">Overview</a>
<br> <a href="#Fundamentals_Coordinates">Coordinates</a>
<br> <a href="#Fundamentals_Colours">Colours</a>
<br> <a href="#Fundamentals_Objects">Objects</a>
<br> <a href="#Fundamentals_Animations">Animations</a>
<br> <a href="#Fundamentals_Lighting">Lighting</a>
<br> <a href="#Fundamentals_BasicDataStructures">Basic Data Structures</a>
<br> <a href="#Fundamentals_Textures">Textures</a>
<br> <a href="#Fundamentals_Sounds">Sounds</a>
</p><p> <a href="#RoomGeometry">II. Room Geometry</a>
<br> <a href="#RoomGeometry_Overview">Overview</a>
<br> <a href="#RoomGeometry_RoomStructures">Room Structures</a>
</p><p> <a href="#FloorData">III. FloorData</a>
</p><p> <a href="#MeshGeometry">IV. Mesh Geometry</a>
</p><p> <a href="#MeshConstructionAndAnimation">V. Mesh Construction and Animation</a>
</p><p> <a href="#NonPlayerCharacterBehaviour">VI. Non-Player Character Behaviour</a>
</p><p> <a href="#Sound">VII. Sound</a>
</p><p> <a href="#Miscellany">VIII. Miscellany</a>
<br> <a href="#Miscellany_Version">Version</a>
</p><p> <a href="#EntireTR2level">IX. The Entire TR2 Level Format</a>
<br> <a href="#EntireLevelFormat_TR2">Tomb Raider II</a>
<br> <a href="#EntireLevelFormat_TR1">Tomb Raider I</a>
<br> <a href="#EntireFileFormat_TR3">Tomb Raider III</a>
</p><p> <a href="#ItemizedDifferencesBetweenTR1andTR2">Itemized Differences between TRI and TRII</a>
</p><p> <a href="#ItemizedDifferencesBetweenTR2andTR3">Itemized Differences between TRII and TRIII</a>
</p><p> <a href="#ItemizedDifferencesBetweenTRandDemos">Itemized Differences between "normal" TRs and Demos</a>
</p><p><a href="#ScriptingWithTOMBPC_DAT">X. Scripting with TOMBPC.DAT</a>
</p><p>
</p><hr>
<center>
<p><a name="Fundamentals"></a><b><u><font size="+1">I. The Fundamentals</font></u></b></p></center>
<p><a name="Fundamentals_Overview"></a><b>Overview:</b> Tomb Raider II
is driven by two sets of files. The script file, TOMBPC.DAT, contains all
the text strings describing the various elements in the game (e.g. the
game engine knows about "Key 1"; it looks in TOMBPC.DAT to determine the
name to be displayed in Lara's inventory, such as "Rusty Key" or "Taste
rostige" or "Clé Rouillée"), the level and cut-scene filenames
(e.g. WALL.TR2, CUT3.TR2), the order in which they are to be played, and
various per-level and per-game configuration options (e.g. what weapons
and objects Lara starts the level with, whether or not the "cheat" codes
work, etc.). The level files, {level-name}.TR2, contain everything about
the level, including the geographical geometry, the geometry (meshes) of
all animate and inanimate objects in the level, all the textures and colour
data, all animation data, index information (and, in TR1, the actual sound
sample data) for all sounds, accessibility maps - everything necessary
to run the game. For whatever reason, Core has included everything in one
file instead of breaking it up into logical groupings; this means that
every level contains all the meshes, textures, sound information, and animation
data for Lara and all of her weapons. There are a fair number of other
redundancies, too.
</p><p><a name="Data_Types"></a> For the purposes of further discussion,
the following are assumed:
<br> <b>bit8</b>
specifies an 8-bit signed integer (range -128..127)
<br> <b>bitu8</b>
specifies an 8-bit unsigned integer (range 0..255)
<br> <b>bit16</b>
specifies a 16-bit signed integer (range -32768..32767)
<br> <b>bitu16</b>
specifies a 16-bit unsigned integer (range 0..65535)
<br> <b>bit32</b>
specifies a 32-bit signed integer (range -2147483648..2147483647)
<br> <b>bitu32</b>
specifies a 32-bit unsigned integer (range 0..4294967295)
<br> All multi-byte integers (bit{u}16, bit{u}32) are
stored in little-endian (Intel-x86, etc.) format, with the least significant
byte stored first and the most significant byte stored last. When using
this data in platforms with big-endian (PowerPC, etc.) number format, be
sure to reverse the order of bytes.
</p><p>Data alignment is something one has to be careful about. When some entity
gets an address that is a multiple of n, it is said to be n-byte aligned.
The reason it is important here is that some systems prefer multibyte alignment
for multibyte quantities, and compilers for such systems may pad the data
to get the "correct" alignments, thus making the in-memory structures out
of sync with their file counterparts. However, a compiler may be commanded
to use a lower level of alignment, one that will not cause padding. And
for TR's data structures, 2-byte alignment should be successful in nearly
all cases, with exceptions noted below.
</p><p>To set single-byte alignment in <u>Microsoft Visual C++</u>, use the following compiler directive:
</p><pre>#pragma pack(push, tr2, 1)</pre>
To return to the project's default alignment, use the following directive:
<pre>#pragma pack(pop, tr2)</pre>
<p>To achieve 2-byte alignment in <u>Metrowerks CodeWarrior</u>, widely used in
the MacOS, use this compiler directive:
</p><pre>#pragma options align=mac68k</pre>
To return to the project's default alignment, use this directive:
<pre>#pragma options align=reset</pre>
Similar options exist for other compilers.
<p><a name="Fundamentals_Coordinates"></a><b>Coordinates:</b> The world
coordinate system is oriented with the X-Z plane horizontal and Y vertical,
with -Y being "up" (e.g. decreasing Y values indicate increasing altitude).
The world coordinate system is specified using bit32 values; however, the
geography is limited to the +X/+Z quadrant for reasons that are explained
below. Mesh coordinates are relative and are specified using <a href="#Data_Types">bit16</a>s.
There are some additional coordinate values used, such as "the number of
1024-unit blocks between points A and B"; these are simply scaled
versions of more conventional coordinates.
</p><p><a name="Fundamentals_Colours"></a><b>Colours:</b> All colours in TR2
are specified either explicitly (using either the <a href="#struct_tr2_colour">tr2_colour</a>
structure, described below, or the 16-bit ARGB structure) or implicitly,
by indexing one of the palettes. If, for some reason, 16-bit textures
are turned off, all colours and textures use an 8-bit palette that is stored
in the .TR2 file. This palette consists of a 256-element array of
<a href="#struct_tr2_colour">tr2_colour</a>
structures, each designating some colour; textures and other elements
that need to reference a colour specify an index (0..255) into the Palette[]
array. There is also a 16-bit palette, which is used for identifying
colours of solid polygons. The 16-bit palette contains up to 256
four-byte entries; the first three bytes are a <a href="#struct_tr2_colour">tr2_colour</a>,
while the last byte is ignored (set to 0).
<br>The 16-bit textile array, which contains <a href="#struct_tr2_textile16">tr2_textile16</a>
structures, specifies colours using 16-bit ARGB, where the highest bit
(0x8000) is a crude alpha channel (really just simple transparency - 0
::= transparent, 1 ::= opaque). The next 5 bits (0x7c00) specify
the red channel, the next 5 bits (0x03e0) specify the green channel, and
the last 5 bits (0x001f) specify the blue channel, each on a scale from
0..31.
</p><p><a name="Fundamentals_Objects"></a><b>Objects:</b> There are two basic
types of objects in TR2 - meshes and sprites. <b>Meshes</b> are collections
of textured or coloured polygons that are assembled to form a three-dimensional
object (such as a tree, a tiger, or Lara herself). The "rooms" themselves
are also composed of meshes. Mesh objects may contain more than one mesh;
though these meshes are moved relative to each other, each mesh is rigid.
<b>Sprites</b>
are two-dimensional images that are inserted into three-dimensional space,
such as the "secret" dragons, ammunition, medi-packs, etc. There are also
animated sprite sequences, such as the fire at the end of "The Great Wall."
Core had presumably used this method to reduce CPU utilization on the PlayStation
and/or the earlier PCs. Sprites become less and less abundant; TR2 has
very few scenery sprites, and TR3's pickups are models instead of sprites.
Objects are referenced in one of two ways - as an offset into an array
(e.g. Moveables[i]) or using an identifying tag (ObjectID). In the latter
case, the related array (Items[], Moveables[], etc.) is searched until
a matching ObjectID is found.
</p><p><a name="Fundamentals_Animations"></a><b>Animations:</b> There are three
basic types of animations in TR2, two corresponding directly with meshes
and sprites, and a third type, animated textures. Sprite animation (sprite
sequences) consists simply of a series of sprites that are to be displayed
one after another, e.g. grenade explosions. Mesh animations are much more
complex, done by what is essentially a skeletal-modeling scheme. These
involve some arrays (Frames[] and MeshTree[]) of offsets and rotations
for each element of a composite mesh. Frames are then grouped into an array
(Animations[]) that describes discrete "movements," e.g. Lara taking a
step or a tiger striking with its paw. The animations are "sewn together"
by a state change array and an animation dispatch array, which, together
with state information about the character, ensure that the animation is
fluid (e.g. if Lara is running and the player releases the RUN key, she
will stop; depending upon which of her feet was down at the time, either
her left or right foot will strike the floor as part of the "stop" animation.
The correct animation (left foot stop vs. right foot stop) is selected
using these structures and the state information). Animated textures are
simply a list of textures that are cycled through in an endless loop; they
are normally used as geographic elements of the levels (e.g. water surface,
bubbling lava, Atlantean plasma walls).
</p><p><a name="Fundamentals_Lighting"></a><b>Lighting:</b> There are two main
types of lighting in Tomb Raider, constant and vertex. Constant lighting
means that all parts of an object have the same illumination, while in
vertex lighting, each polygon vertex has its own light value, and the illumination
of the polygon interiors is interpolated from the vertex values. Furthermore,
lighting can be either internal or external. Internal lighting is specified
in an object's data, external lighting is calculated using the room's light
sources (ambient light, point light sources, flares, gunshots). Light intensities
are described with a single value in TR1 and a pair of values in TR2 and
TR3; the paired values are almost always equal, and the pairing may reflect
some feature that was only imperfectly implemented, such as off/on or minimum/maximum
values. In TR1 and TR2, the light values go from 0 (maximum light) to 8192
(minimum light), while in TR3, the light values go from 0 (minimum light)
to 32767 (maximum light).
</p><p><a name="Fundamentals_BasicDataStructures"></a><b>Basic Data Structures:</b>
Much of the .TR2 file is comprised of structures based on a few fundamental
data structures, described below.
</p><ul>
<li>
<a name="struct_tr2_colour"></a><b>Colour structure</b> - this is how most
colours are specified.</li>
</ul>
typedef struct { // 3 bytes
<br>
<a href="#Data_Types">bitu8</a> Red; // Red component (0 ::= darkest, 255 ::= brightest)
<br>
<a href="#Data_Types">bitu8</a> Green; // Green component (0 ::= darkest, 255 ::= brightest)
<br>
<a href="#Data_Types">bitu8</a> Blue; // Blue component (0 ::= darkest, 255 ::= brightest)
<br> } <b>tr2_colour</b>;
<br>(Some compilers, like CodeWarrior, will pad this structure to make 4
bytes; one must either read and write 3 bytes explicitly, or else use a
simple array of bytes instead of this structure.)
<p>
And as mentioned earlier, the 16-bit palette uses a similar structure:
</p> typedef struct { // 4 bytes
<br> <a href="#Data_Types">bitu8</a> Red;
<br> <a href="#Data_Types">bitu8</a> Green;
<br> <a href="#Data_Types">bitu8</a> Blue;
<br> <a href="#Data_Types">bitu8</a> Unused;
<br> } <b>tr2_colour4</b>;
<ul>
<li>
<a name="struct_tr2_vertex"></a><b>Vertex structure</b> - this is how vertices
are specified, using relative coordinates. They are generally formed
into lists, such that other entities (such as quads or triangles) can refer
to them by simply using their index in the list.</li>
</ul>
typedef
struct { // 6 bytes
<br>
<a href="#Data_Types">bit16</a> x;
<br>
<a href="#Data_Types">bit16</a> y;
<br>
<a href="#Data_Types">bit16</a> z;
<br>
} <b>tr2_vertex</b>;
<ul>
<li>
<a name="struct_tr2_face4"></a><b>Rectangular (quad) face definition</b>.
Four vertices (the values are indices into the appropriate vertex list)
and a texture (an index into the object-texture list) or colour (index
into 8-bit palette or 16-bit palette). If the rectangle is a coloured
polygon (not textured), the .Texture element contains two indices: the
low byte (.Texture & 0xff) is an index into the 256-colour palette,
while the high byte (.Texture >> 8) is in index into the 16-bit palette,
when present. A textured rectangle will have its vertices mapped onto all
4 vertices of an object texture, in appropriate correspondence.</li>
</ul>
<dir> typedef struct {
// 10 bytes
<br> <a href="#Data_Types">bitu16</a>
Vertices[4];
<br> <a href="#Data_Types">bitu16</a>
Texture;
<br> } <b>tr2_face4</b>;</dir>
<ul>
<li>
<a name="struct_tr2_face3"></a><b>Triangular face definition</b>. Three
vertices (the values are indices into the appropriate vertex list) and
a texture (an index into the object-texture list) or colour (index into
8-bit palette or 16-bit palette). If the triangle is a coloured polygon
(not textured), the .Texture element contains two indices: the low byte
(.Texture & 0xff) is an index into the 256-colour palette, while the
high byte (.Texture >> 8) is in index into the 16-bit palette, when present.
A textured triangle will have its vertices mapped onto the first 3 vertices
of an object texture, in appropriate correspondence.</li>
</ul>
typedef
struct { // 8 bytes
<br>
<a href="#Data_Types">bitu16</a> Vertices[3];
<br>
<a href="#Data_Types">bitu16</a> Texture;
<br>
} <b>tr2_face3</b>;
<br>
<ul>
<li>
<a name="struct_tr2_textile8"></a><b>8-bit texture tile</b> (65536 bytes).
Each <a href="#Data_Types">bitu8</a> represents a pixel whose colour is
in the 8-bit palette.</li>
</ul>
typedef
struct { // 65536 bytes
<br>
<a href="#Data_Types">bitu8</a> Tile[256 * 256];
<br>
} <b>tr2_textile8</b>;
<ul>
<li>
<a name="struct_tr2_textile16"></a><b>16-bit texture tile</b> (131072 bytes).
Each <a href="#Data_Types">bitu16</a> represents a pixel whose colour is
of the form ARGB, MSB-to-LSB:</li>
</ul>
1-bit transparency (0 ::= transparent, 1 ::= opaque) (0x8000)
<br>
5-bit red channel (0x7c00)
<br>
5-bit green channel (0x03e0)
<br>
5-bit blue channel (0x001f)
<p> typedef
struct { // 131072 bytes
<br>
<a href="#Data_Types">bitu16</a> Tile[256 * 256];
<br>
} <b>tr2_textile16</b>;
<br>
</p><p><a name="Fundamentals_Textures"></a><b>Textures:</b> All mesh surfaces
are either <b>coloured</b> or <b>textured</b>. Coloured surfaces
are "painted" with a single colour that is either specified explicitly
or using an index into the palette. Textured surfaces map textures
(bitmapped images) from the texture tiles (textiles) to each point on the
mesh surface. This is done using conventional UV mapping, which is
specified in "Object Textures" below; each object texture specifies a mapping
from a set of vertices to locations in the textile, and these texture vertices
are associated with position vertices specified here.
</p><p><a name="Fundamentals_Sounds"></a>
</p><p>
</p><hr>
<p><b>Sounds:</b> There are several sorts of sounds, which can be classified
as either continuous or triggered. Continuous sounds are level-background
sounds (such as the blowing wind in "The Great Wall") and sound sources
(such as waterfalls; these are in SoundSources[]). Triggered sounds are
sounds played when some event happens, such as at certain animation frames
(footsteps and other Lara sounds), when doors open and close, and when
weapons are fired. Sounds are stored in two places: the game-data files
and the CD audio tracks (the latter are separate soundfiles in the MacOS
version). The latter kind of sound is referred to straightforwardly, by
index, while the former kind of sound is referred to using a three-layer
indexing scheme, to provide a maximum amount of abstraction. An internal
sound index references SoundMap[], which points to a SoundDetails[] record,
which in turn points to a SampleIndices[] entry, which in turn points to
a sound sample. SoundDetails[] contains such features as sound intensity,
how many sound samples to choose from, among others. The sound samples
themselves are in Microsoft WAVE format, and they are embedded either in
the data files (TR1, some later TR demos) or in a separate file (MAIN.SFX)
in TR2 and TR3.
<br>
<br>
<br>
</p><center>
<p><a name="RoomGeometry"></a><b><u><font size="+1">II. Room Geometry</font></u></b></p></center>
<p><a name="RoomGeometry_Overview"></a><b>Overview: </b>A <b>room</b> in
TR2 is simply a rectangular three-dimensional area. A room may be "indoors"
or "outdoors," may or may not be enclosed, may be accessible or inaccessible
to Lara, may or may not contain doors or objects. All rooms have "portals,"
called "doors" in some documentation, which are pathways to adjacent rooms.
There are two kinds of portals, visibility portals and collisional portals.
Visibility portals are for determining how much of a room (if any) is visible
from another room, while collisional portals are for enabling an object
to travel from one room to another. The visibility portals are most likely
for doing "portal rendering", which is a visibility-calculation scheme
that goes as follows: The viewpoint is a member of some room, which is
then listed as visible from it. This room's portals are checked for visibility
from that viewpoint, and visible portals have their opposite-side rooms
marked as visible. These rooms are then checked for portals that are visible
from the viewpoint through the viewpoint's room's portals, and visible
ones have their opposite-side rooms marked as visible. This operation is
repeated, with viewing through intermediate portals, until all visible
portals have been found. The result is a tree of rooms, starting from the
viewpoint's room; only those rooms and their contents need be rendered.
It is clear that both visibility and collision calculations require that
objects have room memberships given for them, and indeed we shall find
that most map objects have room memberships.
</p><p>Rooms may overlap; as we shall see, this is involved in how horizontal
collisional portals are implemented. However, different rooms may overlap
without either being directly accessible from the other; there are several
inadvertent examples of such "5D space" in the Tomb Raider series. The
only possibly deliberate example I know of is the flying saucer in "Area
51" in TR3, whose interior is bigger than its exterior.
</p><p>A room can have an "alternate room" specified for it; that means that
that room can be replaced by that alternate as the game is running. This
trick is used to produce such tricks as empty rooms vs. rooms full of water,
scenery rearrangements (for example, the dynamited house in "Bartoli's
Hideout" in TR2), and so forth. An empty room is first created, and then
a full room is created at its location from a copy of it. The empty room
then has that full room set as its alternate, and when that room is made
to alternate, one sees a full room rather than an empty one.
</p><p>The rooms are stored sequentially in an array, and "Room Numbers" are
simply indices into this array (e.g. "Room Number 5" is simply Rooms[5];
the first room is Rooms[0]).
</p><p>Rooms are divided into <b>Sectors</b>, which are 1024x1024 unit squares
that form a grid on the X-Z plane. Sectors are the defining area
for floor/ceiling height and various actions (e.g. a tiger appears and
attacks when Lara steps on a given square); the various attributes
of each sector are stored in the Sector Data (described in this section)
and the <a href="#FloorData">FloorData</a>. As an aside, Sectors
correspond to the "squares," easily visible in all of the Tomb Raider games,
that experienced players count when gauging jumps; they also account
for some of the game's less-appealing graphic artifacts. Careful tiling
and texture construction can make these "squares" almost invisible.
</p><p>Rooms have two kinds of surfaces, rendered and collisional, much like
the two kinds of portals. The former are what is seen, while the latter
control how objects interact with the world geometry. Furthermore, these
two types are specified separately in the room data.
</p><p>Rooms are defined with a complex structure, which is described below
"inside-out," meaning that the smaller component structures are described
first, followed by the larger structures that are built using the smaller
structures.
</p><p><a name="RoomGeometry_RoomStructures"></a><b>Room Structures:</b>
</p><ul>
<li>
<a name="struct_tr2_room_info"></a><b>Room header.</b> X/Z indicate
the base position of the room mesh in world coordinates (Y is always zero-relative)</li>
</ul>
<dir> typedef struct {
// 16 bytes
<br> <a href="#Data_Types">bit32</a>
x;
// X-offset of room (world coordinates)
<br> <a href="#Data_Types">bit32</a>
z;
// Z-offset of room (world coordinates)
<br> <a href="#Data_Types">bit32</a>
yBottom; // (actually largest value,
but indicates lowest point in room)
<br> <a href="#Data_Types">bit32</a>
yTop;
// (actually smallest value, but indicates highest point in room)
<br> } <b>tr2_room_info</b>;</dir>
<ul>
<li>
<a name="struct_tr2_room_door"></a><b>Portal structure.</b> These
portals, sometimes called "doors", define the view from a room into another
room. This can be through a "real" door, a window, or even some open area
that makes the rooms look like one big room. Note that "rooms" here are
really just areas; they aren't necessarily enclosed. The portal structure
below defines visibility portals, not an actual moveable door mesh, texture,
or action (if any). And if the portal is not properly oriented, the
camera cannot "see" through it.</li>
</ul>
<dir>
<dir>typedef struct
{
//
32 bytes
<br> <a href="#Data_Types">bitu16</a> AdjoiningRoom;
// which room this portal leads to
<br> <a href="#struct_tr2_vertex">tr2_vertex</a> Normal;
// which way the portal faces (the normal
<br> // points <i>away</i> from the adjacent room; to be seen through, it
must point <i>toward</i> the viewpoint).
<br> <a href="#struct_tr2_vertex">tr2_vertex</a> Vertices[4];
// the corners of this portal (the right-hand rule applies with respect
to the normal)
<br> // if the right-hand-rule is not followed, the portal will
<br> // contain visual artifacts instead of a viewport to
<br> // AdjoiningRoom
<br> } <b>tr2_room_portal</b>;</dir>
</dir>
<ul>
<li>
<a name="struct_tr2_room_sector"></a><b>Room Sector structure. All
the geometry specified here is collisional geometry.</b> Sectors are 1024
* 1024 (world coordinates). Floor and Ceiling are signed numbers of 256
units of height (relative to 0), e.g. Floor 0x04 corresponds to Y = 1024
in world coordinates. Note: this implies that, while X and Z can be quite
large, Y is constrained to -32768..32512. Floor/Ceiling value of 0x81 is
used to indicate impenetrable walls around the sector. Floor values are
used by the game engine to determine what objects Lara can traverse and
how. Relative steps of 1 (-256) can be walked up; steps of 2..7 (-512..-1792)
can/must be jumped up; steps larger than 7 (-2048..-32768) cannot be jumped
up (too tall). RoomAbove and RoomBelow indicate what neighboring rooms
are in these directions; if RoomAbove is not "none", then the ceiling is
a collisional portal to that room, while if RoomBelow is not "none", then
the floor is a collisional portal to that room.</li>
</ul>
<dir>
<dir>
<br>typedef struct
{
//
8 bytes
<br> <a href="#Data_Types">bitu16</a> FDindex;
// Index into FloorData[]
<br> <a href="#Data_Types">bitu16</a> BoxIndex;
// Index into Boxes[]/Zones[] (-1 if none)
<br> <a href="#Data_Types">bitu8</a> RoomBelow;
// The number of the room below this one (-1 or 255 if none)
<br> <a href="#Data_Types">bit8</a>
Floor;
// Absolute height of floor (multiply by 256 for world coordinates)
<br> <a href="#Data_Types">bitu8</a> RoomAbove;
// The number of the room above this one (-1 or 255 if none)
<br> <a href="#Data_Types">bit8</a>
Ceiling;
// Absolute height of ceiling (multiply by 256 for world coordinates)
<br> } <b>tr2_room_sector</b>;
<p><font color="#008000">In TR3, BoxIndex is more complicated. Only bits
4-14 are the "real" index; bits 0-3 are most likely some kind of flag,
such as what kind of footstep sound to make (wood, metal, snow). Furthermore,
there is a special value of the "real" index, 2047, or 0x7ff.</font></p></dir>
</dir>
<ul>
<li>
<a name="struct_tr2_room_light"></a><b>Room Lighting structure.</b>
X/Y/Z are in world coordinates. Intensity1/Intensity2 are almost
always equal. This lighting only affects externally-lit objects. Tomb Raider
1 has only the first of the paired Intensity and Fade values.</li>
</ul>
<dir> typedef struct {
// 24 bytes [TR1: 18 bytes]
<br> <a href="#Data_Types">bit32</a>
x;
// X-position of light, in world coordinates
<br> <a href="#Data_Types">bit32</a>
y;
// Y-position of light, in world coordinates
<br> <a href="#Data_Types">bit32</a>
z;
// Z-position of light, in world coordinates
<br> <a href="#Data_Types">bitu16</a>
Intensity1; // Light intensity
<br> <a href="#Data_Types">bitu16</a>
Intensity2; // Almost always equal to Intensity1 [absent
from TR1 data files]
<br> <a href="#Data_Types">bitu32</a>
Fade1; // Falloff value
1
<br> <a href="#Data_Types">bitu32</a>
Fade2; // Falloff value
2 [absent from TR1 data files]
<br> } <b>tr2_room_light</b>;</dir>
<ul>
<li>
<a name="struct_tr2_room_vertex"></a><b>Room Vertex structure.</b>
This defines the vertices within a room. Room lighting is internal vertex
lighting, except for necessarily external sources like flares; room ambient
lights and point sources are ignored. Tomb Raider 1 has only the first
of the two light values and lacks the rendering attributes.</li>
</ul>
<dir>
<dir>typedef struct {
// 12 bytes [TR1: 8 bytes]
<br> <a href="#struct_tr2_vertex">tr2_vertex</a> Vertex;
// where this vertex lies (relative to tr2_room_info::x/z)
<br> <a href="#Data_Types">bit16</a> Lighting1;
<br> <a href="#Data_Types">bitu16</a> Attributes;
// A set of flags for special rendering effects [absent from TR1 data files]
<br> //
0x8000 something to do with water surface
<br>
//
0x4000 under water lighting modulation and
<br> //
movement if viewed from above water surface
<br>
//
0x2000 water/quicksand surface movement
<br>
//
0x0010 "normal"
<br> <a href="#Data_Types">bit16</a> Lighting2;
// Almost always equal to Lighting1 [absent from TR1 data files]
<br> } <b>tr2_vertex_room</b>;</dir>
</dir>
<ul>
<li>
<a name="struct_tr2_room_sprite"></a><b>Room Sprite structure.</b> This
indicates a point in space (Room.Vertices[room_sprite.Vertex]) and a sprite
to display there (.Texture is an index into the sprite texture list).</li>
</ul>
<dir>
<dir>typedef struct { //
4 bytes
<br> <a href="#Data_Types">bit16</a> Vertex;
// offset into vertex list
<br> <a href="#Data_Types">bit16</a> Texture;
// offset into sprite texture list
<br> } <b>tr2_room_sprite</b>;</dir>
</dir>
<ul>
<li>
<a name="struct_tr2_room_data"></a><b>Room Data structure.</b> This
is the geometry of the "room," including walls, floors, rocks, water, etc.
It does <i><u>not</u></i> include objects that Lara can interact with (keyboxes,
moveable blocks, moveable doors, etc.) The surfaces specified here are
rendered surfaces. <b>NOTE</b> that this is not a "real" C/C++ structure,
in that the arrays are sized by the NumXXX elements that precede them.</li>
</ul>
<dir>
<dir>typedef struct
{
//
(variable length)
<br> <a href="#Data_Types">bit16</a>
NumVertices;
//
number of vertices in the following list
<br> <a href="#struct_tr2_room_vertex">tr2_vertex_room</a>
Vertices[NumVertices]; // list of vertices (relative coordinates)
<br> <a href="#Data_Types">bit16</a>
NumRectangles;
//
number of textured rectangles
<br> <a href="#struct_tr2_face4">tr2_face4</a> Rectangles[NumRectangles];
// list of textured rectangles
<br> <a href="#Data_Types">bit16</a>
NumTriangles;
//
number of textured triangles
<br> <a href="#struct_tr2_face3">tr2_face3</a> Triangles[NumTriangles];
// list of textured triangles
<br> <a href="#Data_Types">bit16</a>
NumSprites;
//
number of sprites
<br> <a href="#struct_tr2_room_sprite">tr2_room_sprite</a>
Sprites[NumSprites]; // list of sprites
<br> } <b>tr2_room_data</b>;</dir>
</dir>
<ul>
<li>
<a name="struct_tr2_room_staticmesh"></a><b>Room Static Mesh structure.</b>
Positions and IDs of static meshes (e.g. skeletons, spiderwebs, furniture,
trees). This is comparable to the <a href="#struct_tr2_item">tr2_item</a>
structure, except that static meshes typically have no animations and are
confined to a single room.</li>
</ul>
<dir>
<dir>typedef struct { // 20 bytes
<font color="#800000">[TR1: 18 bytes]</font>
<br> <a href="#Data_Types">bitu32</a> x;
// absolute X position in world coordinates
<br> <a href="#Data_Types">bitu32</a> y;
// absolute Y position in world coordinates
<br> <a href="#Data_Types">bitu32</a> z;
// absolute Z position in world coordinates
<br> <a href="#Data_Types">bitu16</a> Rotation;
// high two bits (0xC000) indicate steps of
<br> //
90 degrees (e.g. (Rotation >> 14) * 90)
<br> <a href="#Data_Types">bitu16</a> Intensity1; //
Constant lighting; -1 means use mesh lighting
<br> <a href="#Data_Types">bitu16</a> Intensity2; //
Like Intensity 1, and almost always the same value [absent from TR1 data
files]
<br> <a href="#Data_Types">bitu16</a> ObjectID;
// which StaticMesh item to draw
<br> } <b>tr2_room_staticmesh</b>;</dir>
</dir>
<ul>
<li>
<a name="struct_tr2_room"></a><b>Room structure.</b> Here's where
all the room data come together. As it's stored in the file, the
<a href="#struct_tr2_room_info">tr2_room_info</a>
structure comes first, followed by a <a href="#Data_Types">bitu32</a> NumDataWords,
which specifies the number of 16-bit words to follow. Those data
words must be parsed in order to interpret and construct the variable-length
arrays of vertices, meshes, doors, and sectors. <b>NOTE</b> that
this is not a "real" C/C++ structure, in that the arrays are sized by the
NumXXX elements that precede them.</li>
</ul>
<blockquote>typedef struct
{
//
(variable length)
<br> <a href="#struct_tr2_room_info">tr2_room_info</a>
info;
//
where the room exists, in world coordinates
<br> <a href="#Data_Types">bitu32</a> NumDataWords;
// number of data words (bitu16s)
<br> <a href="#Data_Types">bitu16</a> Data[NumDataWords];
// the raw data from which the rest of
<br> //
this is derived
<br> <a href="#struct_tr2_room_data">tr2_room_data</a>
RoomData;
// the room mesh
<br> <a href="#Data_Types">bitu16</a>
NumPortals;
//
number of visibility portals to other rooms
<br> <a href="#struct_tr2_room_portal">tr2_room_portal</a>
Portals[NumPortals]; // list of visibility portals
<br> <a href="#Data_Types">bitu16</a>
NumZsectors;
//
"width" of sector list
<br> <a href="#Data_Types">bitu16</a>
NumXsectors;
//
"height" of sector list
<br> <a href="#struct_tr2_room_sector">tr2_room_sector</a>
SectorList[NumXsectors * NumZsectors]; // list of sectors
<br> //
in this room
<br> <a href="#Data_Types">bit16</a> AmbientIntensity1;
// This and the next one only affect
<br> //
externally-lit objects
<br> <a href="#Data_Types">bit16</a> AmbientIntensity2;
// Almost always the same value as AmbientIntensity1 [absent from TR1 data
files]
<br> <a href="#Data_Types">bit16</a>
LightMode;
//
(present only in TR2: 0 is normal, 1 is
<br> //
flickering(?), 2 and 3 are uncertain)
<br> <a href="#Data_Types">bitu16</a>
NumLights;
//
number of point lights in this room
<br> <a href="#struct_tr2_room_light">tr2_room_light</a>
Lights[NumLights]; // list of point lights
<br> <a href="#Data_Types">bitu16</a> NumStaticMeshes;
// number of static meshes
<br> <a href="#struct_tr2_room_staticmesh">tr2_room_staticmesh</a>
StaticMeshes[NumStaticMeshes]; // list of static meshes
<br> <a href="#Data_Types">bit16</a>
AlternateRoom;
//
number of the room that this room can alternate
<br> //
with (e.g. empty/filled with water is implemented as an empty room
that alternates with a full room)
<br> <a href="#Data_Types">bit16</a> Flags;
// flag bits: 0x0001 - room is filled with water,
<br> //
0x0020 - Lara's ponytail gets blown
<br> //
by the wind;
<br> //
<font color="#FF0000">TR1 has only the water flag and the extra</font>
<br> //
<font color="#FF0000">unknown flag 0x0100.</font>
<br> //
<font color="#008000">TR3 most likely has flags for "is raining",
"is snowing", "water is cold", and "is</font>
<br> //
<font color="#008000">filled by quicksand", among others.</font>
<br> <a href="#struct_tr2_colour">tr2_colour</a><font color="#008000">
RoomLightColour; // Present in TR3 only; absent from TR1/TR2.</font>
<br> } <b>tr2_room</b>;</blockquote>
<hr>
<center>
<p><a name="FloorData"></a><b><u><font size="+1">III. FloorData</font></u></b></p></center>
<p>The <b>FloorData</b> defines special sector attributes such as floor
and ceiling slopes, collisional portals to other rooms, climbability of
walls, and all the various types of triggering. It is referenced by the
sectors as an array of 16-bit unsigned integers, e.g. the current sector
is calculated as (((CurrentX - tr2_room_info.x) / 1024) * tr2_room.NumZsectors)
+ ((CurrentZ - tr2_room_info.z) / 1024), which is then used as an offset
into tr2_room:: SectorList[]; tr2_room_sector::FDindex is an offset into
the FloorData[] array.
</p><p>The FloorData consists of opcodes and operands. Opcodes are 16
bits, as follows:
<br> <b>Function</b>:
bits 0..7 (0x00FF)
<br> <b>SubFunction</b>:
bits 8..14 (0x7F00)
<br> <b>EndData</b>:
bit 15 (0x8000)
<br>If <i>EndData</i> is set, there are no more opcodes (after the current
one) in this section of FloorData; otherwise, the next opcode in
FloorData should be interpreted after the current one.
</p><p>Some functions reference an <b>FDlist</b>, which is a separate list
of opcodes and operands that immediately follows the current FloorData
opcode. FDlist opcodes and operands are different from the base FloorData
opcodes and operands:
<br> <b>FDfunction: </b>bits
10-13 (0x3C00)
<br> <b>Operands: </b>bits
0-9 (0x03FF) vary, depending on FDfunction
<br> <b>FDcontinue: </b>bit
15 (0x8000)
</p><p>Several of the functions indicate adjustments to the sector's floor
and ceiling heights; these are specified by adjusting the corner heights.
The corners will be denoted as 00, 01, 10, and 11; the first is the corner's
X coordinate and the second is the corner's Z coordinate, with both given
as multiples of 1024.
</p><p><font color="#008000">When parsing functions for TR3, use only the lower
5 bits to find the function value, because some of TR3's functions use
the upper 3 bits of the lower byte as part of the operand. However, this
will also work correctly in TR1 and TR2.</font>
</p><p><b><u><font size="+1">FloorData Functions are described below.</font></u></b>
<br> Function 0x01: <b>Portal Sector</b>
<br> SubFunction 0x00: Room Portal:
the next FloorData element (the operand) is the number of the room that
this sector is a collisional portal to.
<br> An entity that arrives in
a sector with this function present will gets its room membership changed
to this function's operand, without any change in position.
</p><p> Function 0x02: <b>Floor Slant</b>
<br> SubFunction 0x00: Floor
Slant: The next FloorData element contains the slant values for the floor
of this sector. Slant values are specified in increments of 256 units.
The high byte (bit8) is the Z slope, while the low byte (bit8) 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.
</p><p> Function 0x03: <b>Ceiling Slant</b>
<br> SubFunction 0x00: Ceiling
Slant: The next FloorData element contains the slant values for the ceiling
of this sector. Slant values are specified in increments of 256 units.
The high byte (bit8) is the Z slope, while the low byte (bit8) 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.
</p><p> Function 0x04: <b>Trigger</b> items, switch cameras,
end the level and much more.
<br>As used below, "run FDlist(activate or deactivate)" means go through
each element in FDlist and perform its function ("run FDlist+1" just means
start at FDlist[1] rather than FDlist[0]). Activate/deactivate is
only used for the activate/deactivate item function.
<br>There are two states for each item, active/inactive (the meaning depends
on the item, e.g. a tiger must be active to be seen, if a door is active
it is open, if it is inactive it is closed, etc.) and on/off (keyholes
and switches).
<br>The <b>bitu16</b> immediately following the 0x04 FloorData opcode contains
flags; the bits at 0x3e00 are the Activation Mask (which is XORed with
any appropriate item flags), the bit at 0x0100 indicates "state change
occurs only once". A good example of activation-mask use is the multiple-switch
room of "Palace Midas" in TR1.
<br> SubFunction 0x00: Run FDlist(activate)
<br> SubFunction 0x01: If Lara
is on the ground, run FDlist(activate)
<br> SubFunction 0x02: If item
at FDlist[0] is on, run FDlist+1(activate), else run FDlist+1(deactivate)
<br> SubFunction 0x03: If item
at FDlist[0] is on, run FDlist+1(activate)
<br> SubFunction 0x04: If item
at FDlist[0] is picked up, run FDlist+1(activate)
<br> SubFunction 0x05: If item
at FDlist[0] is in this sector, run FDlist+1(activate), else run FDlist+1(deactivate)
<br> SubFunction 0x06: If Lara
is on the ground, run FDlist(deactivate)
<br> SubFunction 0x07: unknown
<br> SubFunction 0x08: If Lara
is not on the ground, run FDlist(activate)
<br>
(mainly used for activating collision detection with such objects as footbridges)
<br> SubFunction 0x09: Run FDlist(deactivate)
</p><p> Function 0x05: <b>Kills Lara</b>
<br> Any SubFunction: If Lara
is on the ground, it kills Lara with fire.
</p><p> Function 0x06: <b>Climbable Walls</b>
<br> This 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.
</p><p><font color="#008000"> Functions 0x07
to 0x12: (only in TR3) These specify the floor and ceiling slopes, which
are more complicated here, since these functions 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). The function word
must be parsed as follows:</font>
</p><p><font color="#008000">Bit 15: Continuation bit</font>
<br><font color="#008000">Bits 10-14: value t01</font>
<br><font color="#008000">Bits 5-9: value t00</font>
<br><font color="#008000">Bits 0-4 function value</font>
</p><p><font color="#008000">where t00 and t01 are signed.</font>
</p><p><font color="#008000">It is followed by one operand, to be parsed as
follows:</font>
</p><p><font color="#008000">Bits 12-15: value t13</font>
<br><font color="#008000">Bits 8-11: value t12</font>
<br><font color="#008000">Bits 4-7: value t11</font>
<br><font color="#008000">Bits 0-3: value t10</font>
</p><p><font color="#008000">where t10, t11, t12, and t13 are unsigned.</font>
</p><p><font color="#008000">Here are the triangulations and vertex adjustments;
for some of the functions, one of the triangles is a portal to another
room:</font>
</p><p><font color="#008000">Functions 0x07, 0x0b, 0x0c:</font>
</p><p><font color="#008000">Triangle 1: 00-01-10 (function 0x0b: is a portal)</font>
<br><font color="#008000">Triangle 2: 11-10-01 (function 0x0c: is a portal)</font>
</p><p><font color="#008000">Overall adjustment: adj = t00 + t01 + t10 + t12</font>
</p><p><font color="#008000">Add these quantities to these vertex floor heights:</font>
</p><p><font color="#008000">00: (adj - t11)</font>
<br><font color="#008000">01: (adj - t12)</font>
<br><font color="#008000">10: (adj - t10)</font>
<br><font color="#008000">11: (adj - t13)</font>
</p><p><font color="#008000">Functions 0x08, 0x0d, 0x0e:</font>
</p><p><font color="#008000">Triangle 1: 01-11-00 (function 0x0d: is a portal)</font>
<br><font color="#008000">Triangle 2: 10-00-11 (function 0x0e: is a portal)</font>
</p><p><font color="#008000">Overall adjustment: adj = t00 + t01 + t11 + t13</font>
</p><p><font color="#008000">Add these quantities to these vertex floor heights:</font>
</p><p><font color="#008000">00: (adj - t11)</font>
<br><font color="#008000">01: (adj - t12)</font>
<br><font color="#008000">10: (adj - t10)</font>
<br><font color="#008000">11: (adj - t13)</font>
</p><p><font color="#008000">Functions 0x09, 0x0f, 0x10:</font>
</p><p><font color="#008000">Triangle 1: 00-10-01 (function 0x0f: is a portal)</font>
<br><font color="#008000">Triangle 2: 11-01-10 (function 0x10: is a portal)</font>
</p><p><font color="#008000">Overall adjustment: adj = t10 + t12</font>
</p><p><font color="#008000">Subtract these quantities from these vertex ceiling
heights:</font>
</p><p><font color="#008000">00: (adj - t12)</font>