1 #ifndef H_GAMEFLOW
2 #define H_GAMEFLOW
3 
4 #include "utils.h"
5 #include "lang.h"
6 
7 #define CHECK_FILE(name) if (Stream::existsContent(name)) return name
8 
9 namespace TR {
10 
11     bool useEasyStart;
12     bool isGameEnded;
13 
14     enum {
15         NO_TRACK = 0xFF,
16     };
17 
18     enum Version {
19         VER_UNKNOWN  = 0,
20 
21         VER_PC       = 0x1000,
22         VER_PSX      = 0x2000,
23         VER_SAT      = 0x4000,
24         VER_SDC      = 0x8000,
25 
26         VER_TR1      = 0x01,
27         VER_TR2      = 0x02,
28         VER_TR3      = 0x04,
29         VER_TR4      = 0x08,
30         VER_TR5      = 0x10,
31 
32         VER_VERSION  = VER_TR1 | VER_TR2 | VER_TR3 | VER_TR4 | VER_TR5,
33         VER_PLATFORM = VER_PC  | VER_PSX | VER_SAT | VER_SDC,
34 
35         VER_TR1_PC   = VER_TR1 | VER_PC,
36         VER_TR1_PSX  = VER_TR1 | VER_PSX,
37         VER_TR1_SAT  = VER_TR1 | VER_SAT,
38 
39         VER_TR2_PC   = VER_TR2 | VER_PC,
40         VER_TR2_PSX  = VER_TR2 | VER_PSX,
41 
42         VER_TR3_PC   = VER_TR3 | VER_PC,
43         VER_TR3_PSX  = VER_TR3 | VER_PSX,
44 
45         VER_TR4_PC   = VER_TR4 | VER_PC,
46         VER_TR4_PSX  = VER_TR4 | VER_PSX,
47         VER_TR4_SDC  = VER_TR4 | VER_SDC,
48 
49         VER_TR5_PC   = VER_TR5 | VER_PC,
50         VER_TR5_PSX  = VER_TR5 | VER_PSX,
51         VER_TR5_SDC  = VER_TR5 | VER_SDC,
52 
53         VER_MAX      = 0xFFFFFFFF,
54     };
55 
56     enum LevelID {
57         LVL_CUSTOM,
58     // TR1
59         LVL_TR1_TITLE,
60         LVL_TR1_GYM,
61         LVL_TR1_1,
62         LVL_TR1_2,
63         LVL_TR1_3A,
64         LVL_TR1_3B,
65         LVL_TR1_CUT_1,
66         LVL_TR1_4,
67         LVL_TR1_5,
68         LVL_TR1_6,
69         LVL_TR1_7A,
70         LVL_TR1_7B,
71         LVL_TR1_CUT_2,
72         LVL_TR1_8A,
73         LVL_TR1_8B,
74         LVL_TR1_8C,
75         LVL_TR1_10A,
76         LVL_TR1_CUT_3,
77         LVL_TR1_10B,
78         LVL_TR1_CUT_4,
79         LVL_TR1_10C,
80         LVL_TR1_EGYPT,
81         LVL_TR1_CAT,
82         LVL_TR1_END,
83         LVL_TR1_END2,
84     // TR2
85         LVL_TR2_TITLE,
86         LVL_TR2_ASSAULT,
87         LVL_TR2_WALL,
88         LVL_TR2_CUT_1,
89         LVL_TR2_BOAT,
90         LVL_TR2_VENICE,
91         LVL_TR2_OPERA,
92         LVL_TR2_CUT_2,
93         LVL_TR2_RIG,
94         LVL_TR2_PLATFORM,
95         LVL_TR2_CUT_3,
96         LVL_TR2_UNWATER,
97         LVL_TR2_KEEL,
98         LVL_TR2_LIVING,
99         LVL_TR2_DECK,
100         LVL_TR2_SKIDOO,
101         LVL_TR2_MONASTRY,
102         LVL_TR2_CATACOMB,
103         LVL_TR2_ICECAVE,
104         LVL_TR2_EMPRTOMB,
105         LVL_TR2_CUT_4,
106         LVL_TR2_FLOATING,
107         LVL_TR2_XIAN,
108         LVL_TR2_HOUSE,
109     // TR3
110         LVL_TR3_TITLE,
111         LVL_TR3_HOUSE,
112         LVL_TR3_JUNGLE,
113         LVL_TR3_CUT_6,
114         LVL_TR3_TEMPLE,
115         LVL_TR3_CUT_9,
116         LVL_TR3_QUADCHAS,
117         LVL_TR3_TONYBOSS,
118         LVL_TR3_SHORE,
119         LVL_TR3_CUT_1,
120         LVL_TR3_CRASH,
121         LVL_TR3_CUT_4,
122         LVL_TR3_RAPIDS,
123         LVL_TR3_TRIBOSS,
124         LVL_TR3_ROOFS,
125         LVL_TR3_CUT_2,
126         LVL_TR3_SEWER,
127         LVL_TR3_CUT_5,
128         LVL_TR3_TOWER,
129         LVL_TR3_CUT_11,
130         LVL_TR3_OFFICE,
131         LVL_TR3_NEVADA,
132         LVL_TR3_CUT_7,
133         LVL_TR3_COMPOUND,
134         LVL_TR3_CUT_8,
135         LVL_TR3_AREA51,
136         LVL_TR3_ANTARC,
137         LVL_TR3_CUT_3,
138         LVL_TR3_MINES,
139         LVL_TR3_CITY,
140         LVL_TR3_CUT_12,
141         LVL_TR3_CHAMBER,
142         LVL_TR3_STPAUL,
143     // TR4
144         LVL_TR4_TITLE,
145         LVL_TR4_ANGKOR1,
146         LVL_TR4_ANG_RACE,
147         LVL_TR4_SETTOMB1,
148         LVL_TR4_SETTOMB2,
149         LVL_TR4_JEEPCHAS,
150         LVL_TR4_JEEPCHS2,
151         LVL_TR4_KARNAK1,
152         LVL_TR4_HALL,
153         LVL_TR4_LAKE,
154         LVL_TR4_SEMER,
155         LVL_TR4_SEMER2,
156         LVL_TR4_TRAIN,
157         LVL_TR4_ALEXHUB,
158         LVL_TR4_ALEXHUB2,
159         LVL_TR4_PALACES,
160         LVL_TR4_PALACES2,
161         LVL_TR4_CSPLIT1,
162         LVL_TR4_CSPLIT2,
163         LVL_TR4_LIBRARY,
164         LVL_TR4_LIBEND,
165         LVL_TR4_BIKEBIT,
166         LVL_TR4_NUTRENCH,
167         LVL_TR4_CORTYARD,
168         LVL_TR4_LOWSTRT,
169         LVL_TR4_HIGHSTRT,
170         LVL_TR4_CITNEW,
171         LVL_TR4_JOBY1A,
172         LVL_TR4_JOBY1B,
173         LVL_TR4_JOBY2,
174         LVL_TR4_JOBY3A,
175         LVL_TR4_JOBY3B,
176         LVL_TR4_JOBY4A,
177         LVL_TR4_JOBY4B,
178         LVL_TR4_JOBY4C,
179         LVL_TR4_JOBY5A,
180         LVL_TR4_JOBY5B,
181         LVL_TR4_JOBY5C,
182 
183         LVL_MAX,
184     };
185 
186     enum {
187     // TR1
188         TRACK_TR1_TITLE     = 2,
189         TRACK_TR1_CAVES     = 5,
190         TRACK_TR1_SECRET    = 13,
191         TRACK_TR1_CISTERN   = 57,
192         TRACK_TR1_WIND      = 58,
193         TRACK_TR1_PYRAMID   = 59,
194         TRACK_TR1_CUT_1     = 23,
195         TRACK_TR1_CUT_2     = 25,
196         TRACK_TR1_CUT_3     = 24,
197         TRACK_TR1_CUT_4     = 22,
198     // TR2
199         TRACK_TR2_TITLE     = 64,
200         TRACK_TR2_CHINA_1   = 33,
201         TRACK_TR2_CHINA_2   = 59,
202         TRACK_TR2_ITALY     = 31,
203         TRACK_TR2_RIG       = 58,
204         TRACK_TR2_UNWATER_1 = 34,
205         TRACK_TR2_UNWATER_2 = 31,
206         TRACK_TR2_TIBET_1   = 33,
207         TRACK_TR2_TIBET_2   = 31,
208         TRACK_TR2_CUT_1     = 3,
209         TRACK_TR2_CUT_2     = 4,
210         TRACK_TR2_CUT_3     = 5,
211         TRACK_TR2_CUT_4     = 30,
212     // TR3
213         TRACK_TR3_TITLE     = 5,
214         TRACK_TR3_HOUSE     = 2,
215         TRACK_TR3_CAVES     = 30,
216         TRACK_TR3_INDIA_1   = 34,
217         TRACK_TR3_INDIA_2   = 30,
218         TRACK_TR3_SOUTH_1   = 32,
219         TRACK_TR3_SOUTH_2   = 33,
220         TRACK_TR3_SOUTH_3   = 36,
221         TRACK_TR3_LONDON_1  = 73,
222         TRACK_TR3_LONDON_2  = 74,
223         TRACK_TR3_LONDON_3  = 31,
224         TRACK_TR3_LONDON_4  = 78,
225         TRACK_TR3_NEVADA_1  = 33,
226         TRACK_TR3_NEVADA_2  = 27,
227         TRACK_TR3_ANTARC_1  = 28,
228         TRACK_TR3_ANTARC_2  = 30,
229         TRACK_TR3_ANTARC_3  = 26,
230         TRACK_TR3_CUT_1     = 68,
231         TRACK_TR3_CUT_2     = 67,
232         TRACK_TR3_CUT_3     = 62,
233         TRACK_TR3_CUT_4     = 65,
234         TRACK_TR3_CUT_5     = 63,
235         TRACK_TR3_CUT_6     = 64,
236         TRACK_TR3_CUT_7     = 72,
237         TRACK_TR3_CUT_8     = 70,
238         TRACK_TR3_CUT_9     = 69,
239         TRACK_TR3_CUT_11    = 71,
240         TRACK_TR3_CUT_12    = 66,
241     // TR4
242         TRACK_TR4_BOSS      = 97,
243         TRACK_TR4_JEEP      = 98,
244         TRACK_TR4_BATTLE    = 102,
245         TRACK_TR4_TITLE     = 104,
246         TRACK_TR4_COASTAL   = 105,
247         TRACK_TR4_TRAIN     = 106,
248         TRACK_TR4_IN_DARK   = 107,
249         TRACK_TR4_IN_DRIPS  = 108,
250         TRACK_TR4_WEIRD1    = 109,
251         TRACK_TR4_OUT_DAY   = 110,
252         TRACK_TR4_OUT_NIGHT = 111,
253     };
254 
255     struct LevelInfo {
256         const char *name;
257         StringID   title;
258         uint8      track;
259         uint8      secrets;
260     } LEVEL_INFO[LVL_MAX] = {
261         { ""          , STR_EMPTY         , TRACK_TR1_CAVES     , 0 },
262     // TR1
263         { "TITLE"     , STR_EMPTY         , TRACK_TR1_TITLE     , 0 },
264         { "GYM"       , STR_TR1_GYM       , NO_TRACK            , 0 },
265         { "LEVEL1"    , STR_TR1_LEVEL1    , TRACK_TR1_CAVES     , 3 },
266         { "LEVEL2"    , STR_TR1_LEVEL2    , TRACK_TR1_CAVES     , 3 },
267         { "LEVEL3A"   , STR_TR1_LEVEL3A   , TRACK_TR1_CAVES     , 5 },
268         { "LEVEL3B"   , STR_TR1_LEVEL3B   , TRACK_TR1_CAVES     , 3 },
269         { "CUT1"      , STR_EMPTY         , TRACK_TR1_CUT_1     , 0 },
270         { "LEVEL4"    , STR_TR1_LEVEL4    , TRACK_TR1_WIND      , 4 },
271         { "LEVEL5"    , STR_TR1_LEVEL5    , TRACK_TR1_WIND      , 3 },
272         { "LEVEL6"    , STR_TR1_LEVEL6    , TRACK_TR1_WIND      , 3 },
273         { "LEVEL7A"   , STR_TR1_LEVEL7A   , TRACK_TR1_CISTERN   , 3 },
274         { "LEVEL7B"   , STR_TR1_LEVEL7B   , TRACK_TR1_CISTERN   , 2 },
275         { "CUT2"      , STR_EMPTY         , TRACK_TR1_CUT_2     , 0 },
276         { "LEVEL8A"   , STR_TR1_LEVEL8A   , TRACK_TR1_WIND      , 3 },
277         { "LEVEL8B"   , STR_TR1_LEVEL8B   , TRACK_TR1_WIND      , 3 },
278         { "LEVEL8C"   , STR_TR1_LEVEL8C   , TRACK_TR1_WIND      , 1 },
279         { "LEVEL10A"  , STR_TR1_LEVEL10A  , TRACK_TR1_CISTERN   , 3 },
280         { "CUT3"      , STR_EMPTY         , TRACK_TR1_CUT_3     , 0 },
281         { "LEVEL10B"  , STR_TR1_LEVEL10B  , TRACK_TR1_PYRAMID   , 3 },
282         { "CUT4"      , STR_EMPTY         , TRACK_TR1_CUT_4     , 0 },
283         { "LEVEL10C"  , STR_TR1_LEVEL10C  , TRACK_TR1_PYRAMID   , 3 },
284         { "EGYPT"     , STR_TR1_EGYPT     , TRACK_TR1_WIND      , 3 },
285         { "CAT"       , STR_TR1_CAT       , TRACK_TR1_WIND      , 4 },
286         { "END"       , STR_TR1_END       , TRACK_TR1_WIND      , 2 },
287         { "END2"      , STR_TR1_END2      , TRACK_TR1_WIND      , 1 },
288     // TR2
289         { "TITLE"     , STR_EMPTY         , TRACK_TR2_TITLE     , 0 },
290         { "ASSAULT"   , STR_TR2_ASSAULT   , NO_TRACK            , 0 },
291         { "WALL"      , STR_TR2_WALL      , TRACK_TR2_CHINA_1   , 3 },
292         { "CUT1"      , STR_EMPTY         , TRACK_TR2_CUT_1     , 0 },
293         { "BOAT"      , STR_TR2_BOAT      , NO_TRACK            , 3 },
294         { "VENICE"    , STR_TR2_VENICE    , NO_TRACK            , 3 },
295         { "OPERA"     , STR_TR2_OPERA     , TRACK_TR2_ITALY     , 3 },
296         { "CUT2"      , STR_EMPTY         , TRACK_TR2_CUT_2     , 0 },
297         { "RIG"       , STR_TR2_RIG       , TRACK_TR2_RIG       , 3 },
298         { "PLATFORM"  , STR_TR2_PLATFORM  , TRACK_TR2_RIG       , 3 },
299         { "CUT3"      , STR_EMPTY         , TRACK_TR2_CUT_3     , 0 },
300         { "UNWATER"   , STR_TR2_UNWATER   , TRACK_TR2_UNWATER_1 , 3 },
301         { "KEEL"      , STR_TR2_KEEL      , TRACK_TR2_UNWATER_2 , 3 },
302         { "LIVING"    , STR_TR2_LIVING    , TRACK_TR2_UNWATER_1 , 3 },
303         { "DECK"      , STR_TR2_DECK      , TRACK_TR2_UNWATER_2 , 3 },
304         { "SKIDOO"    , STR_TR2_SKIDOO    , TRACK_TR2_TIBET_1   , 3 },
305         { "MONASTRY"  , STR_TR2_MONASTRY  , NO_TRACK            , 3 },
306         { "CATACOMB"  , STR_TR2_CATACOMB  , TRACK_TR2_TIBET_2   , 3 },
307         { "ICECAVE"   , STR_TR2_ICECAVE   , TRACK_TR2_TIBET_2   , 3 },
308         { "EMPRTOMB"  , STR_TR2_EMPRTOMB  , TRACK_TR2_CHINA_2   , 3 },
309         { "CUT4"      , STR_EMPTY         , TRACK_TR2_CUT_4     , 0 },
310         { "FLOATING"  , STR_TR2_FLOATING  , TRACK_TR2_CHINA_2   , 3 },
311         { "XIAN"      , STR_TR2_XIAN      , TRACK_TR2_CHINA_2   , 3 },
312         { "HOUSE"     , STR_TR2_HOUSE     , NO_TRACK            , 3 },
313     // TR3
314         { "TITLE"     , STR_EMPTY         , TRACK_TR3_TITLE     , 0 },
315         { "HOUSE"     , STR_TR3_HOUSE     , NO_TRACK            , 3 },
316         { "JUNGLE"    , STR_TR3_JUNGLE    , TRACK_TR3_INDIA_1   , 3 },
317         { "CUT6"      , STR_EMPTY         , TRACK_TR3_CUT_6     , 0 },
318         { "TEMPLE"    , STR_TR3_TEMPLE    , TRACK_TR3_INDIA_1   , 3 },
319         { "CUT9"      , STR_EMPTY         , TRACK_TR3_CUT_9     , 0 },
320         { "QUADCHAS"  , STR_TR3_QUADCHAS  , TRACK_TR3_INDIA_1   , 3 },
321         { "TONYBOSS"  , STR_TR3_TONYBOSS  , TRACK_TR3_INDIA_2   , 3 },
322         { "SHORE"     , STR_TR3_SHORE     , TRACK_TR3_SOUTH_1   , 3 },
323         { "CUT1"      , STR_EMPTY         , TRACK_TR3_CUT_1     , 0 },
324         { "CRASH"     , STR_TR3_CRASH     , TRACK_TR3_SOUTH_2   , 3 },
325         { "CUT4"      , STR_EMPTY         , TRACK_TR3_CUT_4     , 0 },
326         { "RAPIDS"    , STR_TR3_RAPIDS    , TRACK_TR3_SOUTH_3   , 3 },
327         { "TRIBOSS"   , STR_TR3_TRIBOSS   , TRACK_TR3_CAVES     , 3 },
328         { "ROOFS"     , STR_TR3_ROOFS     , TRACK_TR3_LONDON_1  , 3 },
329         { "CUT2"      , STR_EMPTY         , TRACK_TR3_CUT_2     , 0 },
330         { "SEWER"     , STR_TR3_SEWER     , TRACK_TR3_LONDON_2  , 3 },
331         { "CUT5"      , STR_EMPTY         , TRACK_TR3_CUT_5     , 0 },
332         { "TOWER"     , STR_TR3_TOWER     , TRACK_TR3_LONDON_3  , 3 },
333         { "CUT11"     , STR_EMPTY         , TRACK_TR3_CUT_11    , 0 },
334         { "OFFICE"    , STR_TR3_OFFICE    , TRACK_TR3_LONDON_4  , 3 },
335         { "NEVADA"    , STR_TR3_NEVADA    , TRACK_TR3_NEVADA_1  , 3 },
336         { "CUT7"      , STR_EMPTY         , TRACK_TR3_CUT_7     , 0 },
337         { "COMPOUND"  , STR_TR3_COMPOUND  , TRACK_TR3_NEVADA_2  , 3 },
338         { "CUT8"      , STR_EMPTY         , TRACK_TR3_CUT_8     , 0 },
339         { "AREA51"    , STR_TR3_AREA51    , TRACK_TR3_NEVADA_2  , 3 },
340         { "ANTARC"    , STR_TR3_ANTARC    , TRACK_TR3_ANTARC_1  , 3 },
341         { "CUT3"      , STR_EMPTY         , TRACK_TR3_CUT_3     , 0 },
342         { "MINES"     , STR_TR3_MINES     , TRACK_TR3_ANTARC_2  , 3 },
343         { "CITY"      , STR_TR3_CITY      , TRACK_TR3_ANTARC_3  , 3 },
344         { "CUT12"     , STR_EMPTY         , TRACK_TR3_CUT_12    , 0 },
345         { "CHAMBER"   , STR_TR3_CHAMBER   , TRACK_TR3_ANTARC_3  , 3 },
346         { "STPAUL"    , STR_TR3_STPAUL    , TRACK_TR3_CAVES     , 3 },
347     // TR4
348         { "title"     , STR_UNKNOWN       , TRACK_TR4_TITLE     , 0 },
349         { "angkor1"   , STR_UNKNOWN       , TRACK_TR4_OUT_DAY   , 0 },
350         { "ang_race"  , STR_UNKNOWN       , TRACK_TR4_OUT_DAY   , 0 },
351         { "settomb1"  , STR_UNKNOWN       , TRACK_TR4_IN_DARK   , 0 },
352         { "settomb2"  , STR_UNKNOWN       , TRACK_TR4_IN_DARK   , 0 },
353         { "jeepchas"  , STR_UNKNOWN       , TRACK_TR4_OUT_DAY   , 0 },
354         { "jeepchs2"  , STR_UNKNOWN       , TRACK_TR4_JEEP      , 0 },
355         { "karnak1"   , STR_UNKNOWN       , TRACK_TR4_OUT_DAY   , 0 },
356         { "hall"      , STR_UNKNOWN       , TRACK_TR4_OUT_DAY   , 0 },
357         { "lake"      , STR_UNKNOWN       , TRACK_TR4_OUT_DAY   , 0 },
358         { "semer"     , STR_UNKNOWN       , TRACK_TR4_IN_DARK   , 0 },
359         { "semer2"    , STR_UNKNOWN       , TRACK_TR4_IN_DARK   , 0 },
360         { "train"     , STR_UNKNOWN       , TRACK_TR4_TRAIN     , 0 },
361         { "alexhub"   , STR_UNKNOWN       , TRACK_TR4_OUT_DAY   , 0 },
362         { "alexhub2"  , STR_UNKNOWN       , TRACK_TR4_COASTAL   , 0 },
363         { "palaces"   , STR_UNKNOWN       , TRACK_TR4_IN_DARK   , 0 },
364         { "palaces2"  , STR_UNKNOWN       , TRACK_TR4_IN_DARK   , 0 },
365         { "csplit1"   , STR_UNKNOWN       , TRACK_TR4_IN_DRIPS  , 0 },
366         { "csplit2"   , STR_UNKNOWN       , TRACK_TR4_IN_DRIPS  , 0 },
367         { "library"   , STR_UNKNOWN       , TRACK_TR4_IN_DRIPS  , 0 },
368         { "libend"    , STR_UNKNOWN       , TRACK_TR4_WEIRD1    , 0 },
369         { "bikebit"   , STR_UNKNOWN       , TRACK_TR4_BATTLE    , 0 },
370         { "nutrench"  , STR_UNKNOWN       , TRACK_TR4_BATTLE    , 0 },
371         { "cortyard"  , STR_UNKNOWN       , TRACK_TR4_BATTLE    , 0 },
372         { "lowstrt"   , STR_UNKNOWN       , TRACK_TR4_BATTLE    , 0 },
373         { "highstrt"  , STR_UNKNOWN       , TRACK_TR4_BATTLE    , 0 },
374         { "citnew"    , STR_UNKNOWN       , TRACK_TR4_BATTLE    , 0 },
375         { "joby1a"    , STR_UNKNOWN       , TRACK_TR4_OUT_NIGHT , 0 },
376         { "joby1b"    , STR_UNKNOWN       , TRACK_TR4_IN_DARK   , 0 },
377         { "joby2"     , STR_UNKNOWN       , TRACK_TR4_IN_DARK   , 0 },
378         { "joby3a"    , STR_UNKNOWN       , TRACK_TR4_OUT_NIGHT , 0 },
379         { "joby3b"    , STR_UNKNOWN       , TRACK_TR4_IN_DARK   , 0 },
380         { "joby4a"    , STR_UNKNOWN       , TRACK_TR4_OUT_NIGHT , 0 },
381         { "joby4b"    , STR_UNKNOWN       , TRACK_TR4_IN_DARK   , 0 },
382         { "joby4c"    , STR_UNKNOWN       , TRACK_TR4_OUT_NIGHT , 0 },
383         { "joby5a"    , STR_UNKNOWN       , TRACK_TR4_IN_DARK   , 0 },
384         { "joby5b"    , STR_UNKNOWN       , TRACK_TR4_BOSS      , 0 },
385         { "joby5c"    , STR_UNKNOWN       , TRACK_TR4_IN_DRIPS  , 0 },
386     };
387 
388     static const char* TRACK_LIST_TR4[] = {
389           "044_Attack_part_i"
390         , "008_VonCroy9a"
391         , "100_Attack_part_ii"
392         , "010_VonCroy10"
393         , "015_VonCroy14"
394         , "073_Secret"
395         , "109_Lyre_01"
396         , "042_Action_Part_iv"
397         , "043_Action_Part_v"
398         , "030_VonCroy30"
399         , "012_VonCroy11b"
400         , "011_VonCroy11a"
401         , "063_Misc_Inc_01"
402         , "014_VonCroy13b"
403         , "111_charmer"
404         , "025_VonCroy24b"
405         , "023_VonCroy23"
406         , "006_VonCroy7"
407         , "024_VonCroy24a"
408         , "110_Lyre_02"
409         , "020_VonCroy19"
410         , "034_VonCroy34"
411         , "054_General_Part_ii"
412         , "036_VonCroy36"
413         , "004_VonCroy5"
414         , "035_VonCroy35"
415         , "027_VonCroy27"
416         , "053_General_Part_i"
417         , "022_VonCroy22b"
418         , "028_VonCroy28_L11"
419         , "003_VonCroy4"
420         , "001_VonCroy2"
421         , "041_Action_Part_iii"
422         , "057_General_Part_v"
423         , "018_VonCroy17"
424         , "064_Misc_Inc_02"
425         , "033_VonCroy33"
426         , "031_VonCroy31_L12"
427         , "032_VonCroy32_L13"
428         , "016_VonCroy15"
429         , "065_Misc_Inc_03"
430         , "040_Action_Part_ii"
431         , "112_Gods_part_iv"
432         , "029_VonCroy29"
433         , "007_VonCroy8"
434         , "013_VonCroy12_13a_Lara4"
435         , "009_VonCroy9b_Lara3"
436         , "081_dig"
437         , "085_intro"
438         , "071_Ominous_Part_i"
439         , "095_phildoor"
440         , "061_In_The_Pyramid_Part_i"
441         , "050_Underwater_Find_part_i"
442         , "058_Gods_Part_i"
443         , "005_VonCroy6_Lara2"
444         , "045_Authentic_TR"
445         , "060_Gods_Part_iii"
446         , "055_General_Part_iii"
447         , "059_Gods_Part_ii"
448         , "068_Mystery_Part_ii"
449         , "076_captain2"
450         , "019_Lara6_VonCroy18"
451         , "002_VonCroy3"
452         , "066_Misc_Inc_04"
453         , "067_Mystery_Part_i"
454         , "038_A_Short_01"
455         , "088_key"
456         , "017_VonCroy16_lara5"
457         , "026_VC25_L9_VC26_L10"
458         , "056_General_Part_iv"
459         , "021_VC20_L7_VC21_L8_VC22a"
460         , "096_sarcoph"
461         , "087_jeepB"
462         , "091_minilib1"
463         , "086_jeepA"
464         , "051_Egyptian_Mood_Part_i"
465         , "078_croywon"
466         , "092_minilib2"
467         , "083_horus"
468         , "049_Close_to_the_End_part_ii"
469         , "037_VC37_L15_VC38"
470         , "097_scorpion"
471         , "089_larawon"
472         , "094_minilib4"
473         , "098_throne"
474         , "048_Close_to_the_End"
475         , "070_Mystery_Part_iv"
476         , "093_minilib3"
477         , "072_Puzzle_part_i"
478         , "074_backpack"
479         , "069_Mystery_Part_iii"
480         , "052_Egyptian_Mood_Part_ii"
481         , "084_inscrip"
482         , "099_whouse"
483         , "047_Boss_02"
484         , "080_crypt2"
485         , "090_libend"
486         , "046_Boss_01"
487         , "062_Jeep_Thrills_max"
488         , "079_crypt1"
489         , "082_finale"
490         , "075_captain1"
491         , "105_A5_Battle"
492         , "077_crocgod"
493         , "039_TR4_Title_Q10"
494         , "108_A8_Coastal"
495         , "107_A7_Train+"
496         , "101_A1_In_Dark"
497         , "102_A2_In_Drips"
498         , "104_A4_Weird1"
499         , "106_A6_Out_Day"
500         , "103_A3_Out_Night"
501     };
502 
getGameVersionByLevel(LevelID id)503     Version getGameVersionByLevel(LevelID id) {
504         if (id >= LVL_TR1_TITLE && id <= LVL_TR1_END2)
505             return VER_TR1;
506         if (id >= LVL_TR2_TITLE && id <= LVL_TR2_HOUSE)
507             return VER_TR2;
508         if (id >= LVL_TR3_TITLE && id <= LVL_TR3_STPAUL)
509             return VER_TR3;
510         if (id >= LVL_TR4_TITLE && id <= LVL_TR4_JOBY5C)
511             return VER_TR4;
512         return VER_UNKNOWN;
513     }
514 
getLevelID(int size,const char * name,Version & version,bool & isDemoLevel)515     LevelID getLevelID(int size, const char *name, Version &version, bool &isDemoLevel) {
516         isDemoLevel = false;
517         switch (size) {
518         // TR1
519             // TITLE
520             case 585648  : // PSX JAP
521             case 508614  : version = VER_TR1_PSX;
522             case 5148    : // SAT
523             case 320412  : // PC JAP
524             case 334874  :
525             case 316138  :
526             case 316518  : // PC G
527             case 316460  : return LVL_TR1_TITLE;
528             // GYM
529             case 1234800 : // PSX JAP
530             case 1074234 : version = VER_TR1_PSX;
531             case 343854  : // SAT
532             case 3377974 : // PC JAP
533             case 3236806 :
534             case 3282970 : // PC G
535             case 3237128 : return LVL_TR1_GYM;
536             // LEVEL1
537             case 1667568 : // PSX JAP
538             case 1448896 : version = VER_TR1_PSX;
539             case 497656  : // SAT
540             case 2540906 : // PC JAP
541             case 2533312 :
542             case 2533634 : return LVL_TR1_1;
543             // LEVEL2
544             case 2873406 : isDemoLevel = true; return LVL_TR1_2;
545             case 1766352 : // PSX JAP
546             case 1535734 : version = VER_TR1_PSX;
547             case 532250  : // SAT
548             case 2880722 : // PC JAP
549             case 2873128 :
550             case 2873450 : return LVL_TR1_2;
551             // LEVEL3A
552             case 1876896 : // PSX JAP
553             case 1630560 : version = VER_TR1_PSX;
554             case 547782  : // SAT
555             case 2942002 : // PC JAP
556             case 2934408 :
557             case 2934730 : return LVL_TR1_3A;
558             // LEVEL3B
559             case 1510414 : // PSX JAP
560             case 1506614 : version = VER_TR1_PSX;
561             case 310960  : // SAT
562             case 2745530 : // PC JAP
563             case 2737936 :
564             case 2738258 : return LVL_TR1_3B;
565             // CUT1
566             case 722402  : version = VER_TR1_PSX;
567             case 142116  : // SAT
568             case 599840  : return LVL_TR1_CUT_1;
569             // LEVEL4
570             case 1624130 : // PSX JAP
571             case 1621970 : version = VER_TR1_PSX;
572             case 440612  : // SAT
573             case 3038144 : // PC JAP
574             case 3030550 :
575             case 3030872 : return LVL_TR1_4;
576             // LEVEL5
577             case 1588102 : // PSX JAP
578             case 1585942 : version = VER_TR1_PSX;
579             case 389996  : // SAT
580             case 2725812 : // PC JAP
581             case 2718218 :
582             case 2718540 : return LVL_TR1_5;
583             // LEVEL6
584             case 1710624 : // PSX JAP
585             case 1708464 : version = VER_TR1_PSX;
586             case 573506  : // SAT
587             case 3147184 : // PC JAP
588             case 3139590 :
589             case 3074376 : return LVL_TR1_6;
590             // LEVEL7A
591             case 1698824 : // PSX JAP
592             case 1696664 : version = VER_TR1_PSX;
593             case 581416  : // SAT
594             case 2824884 : // PC JAP
595             case 2817290 :
596             case 2817612 : return LVL_TR1_7A;
597             // LEVEL7B
598             case 1735434 : // PSX JAP
599             case 1733274 : version = VER_TR1_PSX;
600             case 596416  : // SAT
601             case 3603912 : // PC JAP
602             case 3388774 :
603             case 3395618 : // PC G
604             case 3389096 : return LVL_TR1_7B;
605             // CUT2
606             case 542960  : version = VER_TR1_PSX;
607             case 70860   : // SAT
608             case 354320  : return LVL_TR1_CUT_2;
609             // LEVEL8A
610             case 1565494 : // PSX JAP
611             case 1563356 : version = VER_TR1_PSX;
612             case 592188  : // SAT
613             case 2887836 : // PC JAP
614             case 2880242 :
615             case 2880564 : return LVL_TR1_8A;
616             // LEVEL8B
617             case 1567790 : // PSX JAP
618             case 1565630 : version = VER_TR1_PSX;
619             case 599928  : // SAT
620             case 2894028 : // PC JAP
621             case 2886434 :
622             case 2886756 : return LVL_TR1_8B;
623             // LEVEL8C
624             case 1621520 : // PSX JAP
625             case 1619360 : version = VER_TR1_PSX;
626             case 536950  : // SAT
627             case 3072066 : // PC JAP
628             case 3105128 :
629             case 3025380 : // PC G
630             case 3105450 : return LVL_TR1_8C;
631             // LEVEL10A
632             case 1680146 : // PSX JAP
633             case 1678018 : version = VER_TR1_PSX;
634             case 569856  : // SAT
635             case 3270372 : // PC JAP
636             case 3223816 :
637             case 3154346 : // PC G
638             case 3224138 : return LVL_TR1_10A;
639             // CUT3
640             case 636660  : version = VER_TR1_PSX;
641             case 210134  : // SAT
642             case 512104  : return LVL_TR1_CUT_3;
643             // LEVEL10B
644             case 1688908 : // PSX JAP
645             case 1686748 : version = VER_TR1_PSX;
646             case 525646  : // SAT
647             case 3101614 : // PC JAP
648             case 3094342 :
649             case 3094020 : return LVL_TR1_10B;
650             // CUT4
651             case 940398  : version = VER_TR1_PSX;
652             case 167188  : // SAT
653             case 879582  : return LVL_TR1_CUT_4;
654             // LEVEL10C
655             case 1816438 : // PSX JAP
656             case 1814278 : version = VER_TR1_PSX;
657             case 418170  : // SAT
658             case 3533814 : // PC JAP
659             case 3531702 :
660             case 3496692 : // PC G
661             case 3532024 : return LVL_TR1_10C;
662             // EGYPT
663             case 3278614 : version = VER_TR1_PSX;
664             case 3279242 : return LVL_TR1_EGYPT;
665             // CAT
666             case 3270370 : version = VER_TR1_PSX;
667             case 3270998 : return LVL_TR1_CAT;
668             // END
669             case 3208018 : return LVL_TR1_END;
670             // END2
671             case 3153300 : return LVL_TR1_END2;
672         // TR2
673             // TITLE
674             case 148698  : // PSX JAP
675             case 148744  : version = VER_TR2_PSX;
676             case 611892  : return LVL_TR2_TITLE;
677             // ASSAULT
678             case 1568632 : // PSX JAP
679             case 1565974 : version = VER_TR2_PSX;
680             case 3471450 : return LVL_TR2_ASSAULT;
681             // WALL
682             case 1664198 : // PSX JAP
683             case 1661622 : version = VER_TR2_PSX;
684             case 2986356 : return LVL_TR2_WALL;
685             // BOAT
686             case 2017538 : // PSX JAP
687             case 2014880 :
688             case 2010678 : version = VER_TR2_PSX; // PLAYABLE.PSX
689             case 3945738 : return LVL_TR2_BOAT;
690             // VENICE
691             case 2084060 : // PSX JAP
692             case 2081402 : version = VER_TR2_PSX;
693             case 4213070 : return LVL_TR2_VENICE;
694             // OPERA
695             case 2063540 : // PSX JAP
696             case 2060882 : version = VER_TR2_PSX;
697             case 3996500 : return LVL_TR2_OPERA;
698             // RIG
699             case 1952874 : // PSX JAP
700             case 1950216 : version = VER_TR2_PSX;
701             case 3944472 : return LVL_TR2_RIG;
702             // PLATFORM
703             case 1995728 : // PSX JAP
704             case 1993070 : version = VER_TR2_PSX;
705             case 4101590 : return LVL_TR2_PLATFORM;
706             // UNWATER
707             case 1786858 : // PSX JAP
708             case 1784200 : version = VER_TR2_PSX;
709             case 3131814 : return LVL_TR2_UNWATER;
710             // KEEL
711             case 2016768 : // PSX JAP
712             case 2014110 : version = VER_TR2_PSX;
713             case 3995356 : return LVL_TR2_KEEL;
714             // LIVING
715             case 1811102 : // PSX JAP
716             case 1808444 : version = VER_TR2_PSX;
717             case 3501472 : return LVL_TR2_LIVING;
718             // DECK
719             case 1970742 : // PSX JAP
720             case 1968084 : version = VER_TR2_PSX;
721             case 3890042 : return LVL_TR2_DECK;
722             // SKIDOO
723             case 1984560 : // PSX JAP
724             case 1981902 : version = VER_TR2_PSX;
725             case 3521106 : return LVL_TR2_SKIDOO;
726             // MONASTRY
727             case 2123446 : // PSX JAP
728             case 2120772 : version = VER_TR2_PSX;
729             case 4325562 : return LVL_TR2_MONASTRY;
730             // CATACOMB
731             case 1880628 : // PSX JAP
732             case 1877970 : version = VER_TR2_PSX;
733             case 3605052 : return LVL_TR2_CATACOMB;
734             // ICECAVE
735             case 1990512 : // PSX JAP
736             case 1987854 : version = VER_TR2_PSX;
737             case 3803398 : return LVL_TR2_ICECAVE;
738             // EMPRTOMB
739             case 2104252 : // PSX JAP
740             case 2101594 : version = VER_TR2_PSX;
741             case 4291468 : return LVL_TR2_EMPRTOMB;
742             // FLOATING
743             case 2081348 : // PSX JAP
744             case 2078690 : version = VER_TR2_PSX;
745             case 4007486 : return LVL_TR2_FLOATING;
746             // XIAN
747             case 1751496 : // PSX JAP
748             case 1748838 : version = VER_TR2_PSX;
749             case 3173840 : return LVL_TR2_XIAN;
750             // HOUSE
751             case 1889386 : // PSX JAP
752             case 1886728 : version = VER_TR2_PSX;
753             case 3693108 : return LVL_TR2_HOUSE;
754             // CUT1
755             case 952800  : // PSX JAP
756             case 952798  : version = VER_TR2_PSX;
757             case 1767052 : return LVL_TR2_CUT_1;
758             // CUT2
759             case 1098878 : // PSX JAP
760             case 1098876 : version = VER_TR2_PSX;
761             case 2037544 : return LVL_TR2_CUT_2;
762             // CUT3
763             case 1288924 : // PSX JAP
764             case 1288922 : version = VER_TR2_PSX;
765             case 2558286 : return LVL_TR2_CUT_3;
766             // CUT4
767             case 1116968 : // PSX JAP
768             case 1116966 : version = VER_TR2_PSX;
769             case 1900230 : return LVL_TR2_CUT_4;
770         // TR3
771             // TITLE
772             case 653485  : // PSX JAP
773             case 653403  :
774             case 1275266 : return LVL_TR3_TITLE;
775             // HOUSE
776             case 1891244 : // PSX JAP
777             case 1889506 :
778             case 3437855 : return LVL_TR3_HOUSE;
779             // JUNGLE
780             case 1933419 : // PSX JAP
781             case 1930923 :
782             case 3360001 : return LVL_TR3_JUNGLE;
783             // TEMPLE
784             case 1945795 : // PSX JAP
785             case 1943847 :
786             case 3180412 : return LVL_TR3_TEMPLE;
787             // QUADCHAS
788             case 1881562 : // PSX JAP
789             case 1880004 :
790             case 3131453 : return LVL_TR3_QUADCHAS;
791             // TONYBOSS
792             case 1495530 : // PSX JAP
793             case 1493796 :
794             case 2618437 : return LVL_TR3_TONYBOSS;
795             // SHORE
796             case 1981723 : // PSX JAP
797             case 1979611 :
798             case 3365562 : return LVL_TR3_SHORE;
799             // CRASH
800             case 2018552 : // PSX JAP
801             case 2016876 :
802             case 3331132 : return LVL_TR3_CRASH;
803             // RAPIDS
804             case 1942136 : // PSX JAP
805             case 1940346 :
806             case 3148248 : return LVL_TR3_RAPIDS;
807             // TRIBOSS
808             case 1523788 : // PSX JAP
809             case 1521998 :
810             case 2276838 : return LVL_TR3_TRIBOSS;
811             // ROOFS
812             case 2098953 : // PSX JAP
813             case 2097077 :
814             case 3579476 : return LVL_TR3_ROOFS;
815             // SEWER
816             case 2035235 : // PSX JAP
817             case 2033505 :
818             case 3670149 : return LVL_TR3_SEWER;
819             // TOWER
820             case 2080921 : // PSX JAP
821             case 2079183 :
822             case 3523586 : return LVL_TR3_TOWER;
823             // OFFICE
824             case 1550728 : // PSX JAP
825             case 1549006 :
826             case 2504910 : return LVL_TR3_OFFICE;
827             // NEVADA
828             case 1940862 : // PSX JAP
829             case 1938738 :
830             case 3140417 : return LVL_TR3_NEVADA;
831             // COMPOUND
832             case 2050018 : // PSX JAP
833             case 2048288 :
834             case 3554880 : return LVL_TR3_COMPOUND;
835             // AREA51
836             case 2056073 : // PSX JAP
837             case 2054325 :
838             case 3530130 : return LVL_TR3_AREA51;
839             // ANTARC
840             case 2000298 : // PSX JAP
841             case 1998398 :
842             case 3515272 : return LVL_TR3_ANTARC;
843             // MINES
844             case 2025641 : // PSX JAP
845             case 2023895 :
846             case 3331087 : return LVL_TR3_MINES;
847             // CITY
848             case 2058380 : // PSX JAP
849             case 2056388 :
850             case 3575873 : return LVL_TR3_CITY;
851             // CHAMBER
852             case 1782615 : // PSX JAP
853             case 1780885 :
854             case 3190736 : return LVL_TR3_CHAMBER;
855             // STPAUL
856             case 1711157 : // PSX JAP
857             case 1709427 :
858             case 3140028 : return LVL_TR3_STPAUL;
859             // CUT1
860             case 757909  : // PSX JAP
861             case 757827  :
862             case 1547866 : return LVL_TR3_CUT_1;
863             // CUT2
864             case 982847  : // PSX JAP
865             case 982765  :
866             case 1957327 : return LVL_TR3_CUT_2;
867             // CUT3
868             case 1243054 : // PSX JAP
869             case 1242972 :
870             case 2020225 : return LVL_TR3_CUT_3;
871             // CUT4
872             case 430212  : // PSX JAP
873             case 430130  :
874             case 1048466 : return LVL_TR3_CUT_4;
875             // CUT5
876             case 971367  : // PSX JAP
877             case 971285  :
878             case 1580868 : return LVL_TR3_CUT_5;
879             // CUT6
880             case 1325570 : // PSX JAP
881             case 1325488 :
882             case 2430940 : return LVL_TR3_CUT_6;
883             // CUT7
884             case 467203  : // PSX JAP
885             case 467121  :
886             case 1253227 : return LVL_TR3_CUT_7;
887             // CUT8
888             case 494396  : // PSX JAP
889             case 494314  :
890             case 944962  : return LVL_TR3_CUT_8;
891             // CUT9
892             case 1002318 : // PSX JAP
893             case 1002236 :
894             case 1788075 : return LVL_TR3_CUT_9;
895             // CUT11
896             case 590267  : // PSX JAP
897             case 590185  :
898             case 1402003 : return LVL_TR3_CUT_11;
899             // CUT12
900             case 1080128 : // PSX JAP
901             case 1080046 :
902             case 2321393 : return LVL_TR3_CUT_12;
903         // TR4
904             case 3007155 : return LVL_TR4_TITLE;
905             case 4034313 : return LVL_TR4_ANGKOR1;
906             case 4343019 : return LVL_TR4_ANG_RACE;
907             case 3715110 : return LVL_TR4_SETTOMB1;
908             case 3868566 : return LVL_TR4_SETTOMB2;
909             case 3600478 : return LVL_TR4_JEEPCHAS;
910             case 4826055 : return LVL_TR4_JEEPCHS2;
911             case 4773596 : return LVL_TR4_KARNAK1;
912             case 4882065 : return LVL_TR4_HALL;
913             case 5021843 : return LVL_TR4_LAKE;
914             case 4409367 : return LVL_TR4_SEMER;
915             case 4294398 : return LVL_TR4_SEMER2;
916             case 3246177 : return LVL_TR4_TRAIN;
917             case 4007946 : return LVL_TR4_ALEXHUB;
918             case 4735043 : return LVL_TR4_ALEXHUB2;
919             case 4549992 : return LVL_TR4_PALACES;
920             case 4779709 : return LVL_TR4_PALACES2;
921             case 4570232 : return LVL_TR4_CSPLIT1;
922             case 4838007 : return LVL_TR4_CSPLIT2;
923             case 4606099 : return LVL_TR4_LIBRARY;
924             case 3240517 : return LVL_TR4_LIBEND;
925             case 5013974 : return LVL_TR4_BIKEBIT;
926             case 4260336 : return LVL_TR4_NUTRENCH;
927             case 4989001 : return LVL_TR4_CORTYARD;
928             case 3970465 : return LVL_TR4_LOWSTRT;
929             case 4725022 : return LVL_TR4_HIGHSTRT;
930             case 4776907 : return LVL_TR4_CITNEW;
931             case 5011064 : return LVL_TR4_JOBY1A;
932             case 4544163 : return LVL_TR4_JOBY1B;
933             case 4839409 : return LVL_TR4_JOBY2;
934             case 4433722 : return LVL_TR4_JOBY3A;
935             case 5141026 : return LVL_TR4_JOBY3B;
936             case 4786641 : return LVL_TR4_JOBY4A;
937             case 4401690 : return LVL_TR4_JOBY4B;
938             case 4999677 : return LVL_TR4_JOBY4C;
939             case 3741579 : return LVL_TR4_JOBY5A;
940             case 4623726 : return LVL_TR4_JOBY5B;
941             case 4398142 : return LVL_TR4_JOBY5C;
942         }
943 
944         if (name) {
945             // skip directory path
946             int start = 0;
947             for (int i = int(strlen(name)) - 1; i >= 0; i--)
948                 if (name[i] == '/' || name[i] == '\\') {
949                     start = i + 1;
950                     break;
951                 }
952             // skip file extension
953             char buf[255];
954             strcpy(buf, name + start);
955             char *ext = NULL;
956             for (int i = 0; i < int(strlen(buf)); i++)
957                 if (buf[i] == '.') {
958                     buf[i] = 0;
959                     ext = buf + i + 1;
960                     break;
961                 }
962             // compare with standard levels
963             // TODO: fix TITLE (2-3), HOUSE (3), CUTx (2-3)
964             for (int i = 0; i < LVL_MAX; i++)
965                 if (!strcmp(buf, LEVEL_INFO[i].name)) {
966                     LevelID id = LevelID(i);
967                     if (ext) {
968                         version = getGameVersionByLevel(id);
969                         if (!strcmp("PSX", ext)) {
970                             version = Version(version | VER_PSX);
971                         } else if (!strcmp("SAT", ext)) {
972                             version = Version(version | VER_SAT);
973                         } else {
974                             version = Version(version | VER_PC);
975                         }
976                     }
977                     return id;
978                 }
979         }
980 
981         return LVL_CUSTOM;
982     }
983 
getTitleId(Version version)984     LevelID getTitleId(Version version) {
985         switch (version & VER_VERSION) {
986             case VER_TR1 : return LVL_TR1_TITLE;
987             case VER_TR2 : return LVL_TR2_TITLE;
988             case VER_TR3 : return LVL_TR3_TITLE;
989             case VER_TR4 : return LVL_TR4_TITLE;
990         }
991         return LVL_TR1_TITLE;
992         ASSERT(false);
993     }
994 
getHomeId(Version version)995     LevelID getHomeId(Version version) {
996         switch (version & VER_VERSION) {
997             case VER_TR1 : return LVL_TR1_GYM;
998             case VER_TR2 : return LVL_TR2_ASSAULT;
999             case VER_TR3 : return LVL_TR3_HOUSE;
1000             case VER_TR4 : return LVL_MAX;
1001         }
1002         ASSERT(false);
1003         return LVL_MAX;
1004     }
1005 
getStartId(Version version)1006     LevelID getStartId(Version version) {
1007         switch (version & VER_VERSION) {
1008             case VER_TR1 : return LVL_TR1_1;
1009             case VER_TR2 : return LVL_TR2_WALL;
1010             case VER_TR3 : return LVL_TR3_JUNGLE;
1011             case VER_TR4 : return LVL_TR4_ANGKOR1;
1012         }
1013         ASSERT(false);
1014         return LVL_MAX;
1015     }
1016 
getEndId(Version version)1017     LevelID getEndId(Version version) {
1018         switch (version & VER_VERSION) {
1019             case VER_TR1 : return LVL_TR1_10C;
1020             case VER_TR2 : return LVL_TR2_HOUSE;
1021             case VER_TR3 : return LVL_TR3_CHAMBER;
1022             case VER_TR4 : return LVL_TR4_JOBY5C;
1023         }
1024         ASSERT(false);
1025         return LVL_MAX;
1026     }
1027 
isCutsceneLevel(LevelID id)1028     bool isCutsceneLevel(LevelID id) {
1029         return id == LVL_TR1_CUT_1 || id == LVL_TR1_CUT_2 || id == LVL_TR1_CUT_3 || id == LVL_TR1_CUT_4 ||
1030                id == LVL_TR2_CUT_1 || id == LVL_TR2_CUT_2 || id == LVL_TR2_CUT_3 || id == LVL_TR2_CUT_4 ||
1031                id == LVL_TR3_CUT_1 || id == LVL_TR3_CUT_2  || id == LVL_TR3_CUT_3  || id == LVL_TR3_CUT_4 ||
1032                id == LVL_TR3_CUT_5 || id == LVL_TR3_CUT_6  || id == LVL_TR3_CUT_7  || id == LVL_TR3_CUT_8 ||
1033                id == LVL_TR3_CUT_9 || id == LVL_TR3_CUT_11 || id == LVL_TR3_CUT_12;
1034     }
1035 
isTitleLevel(LevelID id)1036     bool isTitleLevel(LevelID id) {
1037         return id == LVL_TR1_TITLE ||
1038                id == LVL_TR2_TITLE ||
1039                id == LVL_TR3_TITLE ||
1040                id == LVL_TR4_TITLE;
1041     }
1042 
isEmptyLevel(LevelID id)1043     bool isEmptyLevel(LevelID id) {
1044         return id == TR::LVL_TR1_10A || id == TR::LVL_TR2_RIG || id == TR::LVL_TR3_COMPOUND;
1045     }
1046 
getGameVersion()1047     Version getGameVersion() {
1048         useEasyStart = true;
1049         if (Stream::existsContent("DATA/GYM.PHD") || Stream::existsContent("GYM.PHD"))
1050             return VER_TR1_PC;
1051         if (Stream::existsContent("PSXDATA/GYM.PSX"))
1052             return VER_TR1_PSX;
1053         if (Stream::existsContent("DATA/GYM.SAT"))
1054             return VER_TR1_SAT;
1055 
1056         if (Stream::existsContent("data/ASSAULT.TR2") || Stream::existsContent("assault.TR2"))
1057             return VER_TR2_PC;
1058         if (Stream::existsContent("DATA/ASSAULT.PSX"))
1059             return VER_TR2_PSX;
1060 
1061         if (Stream::existsContent("data/JUNGLE.TR2"))
1062             return VER_TR3_PC;
1063 
1064         if (Stream::existsContent("DATA/JUNGLE.PSX"))
1065             return VER_TR3_PSX;
1066 
1067         if (Stream::existsContent("data/angkor1.tr4"))
1068             return VER_TR4_PC;
1069 
1070         useEasyStart = false;
1071         return VER_UNKNOWN;
1072     }
1073 
getGameLevelFile(char * dst,Version version,LevelID id)1074     void getGameLevelFile(char *dst, Version version, LevelID id) {
1075         if (useEasyStart) {
1076             switch (version) {
1077                 case VER_TR1_PC  :
1078                     sprintf(dst, "DATA/%s.PHD", LEVEL_INFO[id].name);
1079                     if (Stream::existsContent(dst)) break;
1080                     sprintf(dst, "%s.PHD", LEVEL_INFO[id].name);
1081                     break;
1082                 case VER_TR1_PSX : sprintf(dst, "PSXDATA/%s.PSX", LEVEL_INFO[id].name); break;
1083                 case VER_TR1_SAT : sprintf(dst, "DATA/%s.SAT",    LEVEL_INFO[id].name); break;
1084                 case VER_TR2_PC  : { // oh FFFFUUUUUUCKing CaTaComB.Tr2!
1085                     if (id == LVL_TR2_VENICE || id == LVL_TR2_CUT_2 || id == LVL_TR2_PLATFORM || id == LVL_TR2_CUT_3 || id == LVL_TR2_UNWATER ||
1086                         id == LVL_TR2_KEEL || id == LVL_TR2_LIVING || id == LVL_TR2_DECK || id == LVL_TR2_CATACOMB || id == LVL_TR2_ICECAVE ||
1087                         id == LVL_TR2_CUT_4 || id == LVL_TR2_XIAN || id == LVL_TR2_HOUSE) {
1088                         char buf[64];
1089                         strcpy(buf, LEVEL_INFO[id].name);
1090                         StrUtils::toLower(buf);
1091                         sprintf(dst, "DATA/%s.TR2", buf);
1092                     } else if (id == LVL_TR2_TITLE) {
1093                         sprintf(dst, "DATA/%s.tr2", LEVEL_INFO[id].name);
1094                     } else if (id == LVL_TR2_EMPRTOMB) {
1095                         strcpy(dst, "DATA/Emprtomb.tr2");
1096                     } else {
1097                         sprintf(dst, "DATA/%s.TR2", LEVEL_INFO[id].name);
1098                     }
1099                     if (Stream::existsContent(dst)) break;
1100                     strcpy(dst, LEVEL_INFO[id].name);
1101                     StrUtils::toLower(dst);
1102                     strcat(dst, ".TR2");
1103                     break;
1104                 }
1105                 case VER_TR2_PSX : sprintf(dst, "DATA/%s.PSX", LEVEL_INFO[id].name); break;
1106                 case VER_TR3_PC  : sprintf(dst, isCutsceneLevel(id) ? "cuts/%s.TR2" : "data/%s.TR2", LEVEL_INFO[id].name); break;
1107                 case VER_TR3_PSX : sprintf(dst, isCutsceneLevel(id) ? "CUTS/%s.PSX" : "DATA/%s.PSX", LEVEL_INFO[id].name); break;
1108                 case VER_TR4_PC  : sprintf(dst, "DATA/%s.tr4", LEVEL_INFO[id].name); break;
1109                 default          : ASSERT(false);
1110             }
1111         } else {
1112             strcpy(dst, "level/");
1113             if ((version & VER_TR1) || version == VER_UNKNOWN) strcat(dst, "1/");
1114             if (version & VER_TR2) strcat(dst, "2/");
1115             if (version & VER_TR3) strcat(dst, "3/");
1116             strcat(dst, LEVEL_INFO[id].name);
1117 
1118             #ifdef _OS_WEB
1119                  strcat(dst, ".PSX");
1120             #else
1121                 switch (version) {
1122                     case VER_TR1_PC  : strcat(dst, ".PHD"); break;
1123                     case VER_TR2_PC  :
1124                     case VER_TR3_PC  : strcat(dst, ".TR2"); break;
1125                     case VER_TR1_PSX :
1126                     case VER_TR2_PSX :
1127                     case VER_TR3_PSX : strcat(dst, ".PSX"); break;
1128                     case VER_TR1_SAT : strcat(dst, ".SAT"); break;
1129                     case VER_UNKNOWN :
1130                         if (Stream::existsContent("level/1/TITLE.PSX")) {
1131                             strcpy(dst, "level/1/TITLE.PSX");
1132                             return;
1133                         }
1134                         if (Stream::existsContent("level/1/TITLE.PHD")) {
1135                             strcpy(dst, "level/1/TITLE.PHD");
1136                             return;
1137                         }
1138                         if (Stream::existsContent("level/1/TITLE.SAT")) {
1139                             strcpy(dst, "level/1/TITLE.SAT");
1140                             return;
1141                         }
1142                         if (Stream::existsContent("level/2/TITLE.TR2")) {
1143                             strcpy(dst, "level/2/TITLE.TR2");
1144                             return;
1145                         }
1146                         if (Stream::existsContent("level/2/TITLE.PSX")) {
1147                             strcpy(dst, "level/2/TITLE.PSX");
1148                             return;
1149                         }
1150                         if (Stream::existsContent("level/3/TITLE.TR2")) {
1151                             strcpy(dst, "level/3/TITLE.TR2");
1152                             return;
1153                         }
1154                         if (Stream::existsContent("level/3/TITLE.PSX")) {
1155                             strcpy(dst, "level/3/TITLE.PSX");
1156                             return;
1157                         }
1158                         ASSERT(false); //
1159                         break;
1160                     default : ASSERT(false);
1161                 }
1162             #endif
1163         }
1164     }
1165 
getGameSoundsFile(Version version)1166     const char* getGameSoundsFile(Version version) {
1167         if (version == VER_TR2_PC) {
1168             CHECK_FILE("data/MAIN.SFX");    // PC
1169             CHECK_FILE("MAIN.SFX");         // Android
1170             return "audio/2/MAIN.SFX";      // Web
1171         }
1172 
1173         if (version == VER_TR3_PC) {
1174             CHECK_FILE("data/MAIN.SFX");    // PC
1175             return "audio/3/MAIN.SFX";      // Web
1176         }
1177 
1178         ASSERT(false);
1179         return NULL;
1180     }
1181 
remapTrack(Version version,uint8 track)1182     uint8 remapTrack(Version version, uint8 track) {
1183         static const uint8 TR1_TRACK_MAPPING[] = {
1184             2, 2, 2, 11, 12, 3, 13, 14, 15, 16, 17, 18, 19, 60, 20, 21, 22, 23, 24, 25, 26, 27,
1185             7, 8, 9, 10, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
1186             47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 28, 4, 5, 6
1187         };
1188 
1189         static const uint8 TR2_TRACK_MAPPING[] = {
1190             2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 18, 19, 20,
1191             21, 22, 23, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1192             41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61
1193         };
1194 
1195         if (version & VER_TR1) {
1196             ASSERT(track < COUNT(TR1_TRACK_MAPPING));
1197             return TR1_TRACK_MAPPING[track];
1198         }
1199 
1200         if (version & VER_TR2) {
1201             ASSERT(track < COUNT(TR2_TRACK_MAPPING));
1202             return TR2_TRACK_MAPPING[track];
1203         }
1204 
1205         return track;
1206     }
1207 
checkTrack(const char * pre,char * name)1208     bool checkTrack(const char *pre, char *name) {
1209         static const char *fmt[] = { ".ogg", ".mp3", ".wav" };
1210         const char *lng[] = { "", "", LANG_PREFIXES };
1211 
1212         int start = 1;
1213         if (Core::settings.audio.language != 0) {
1214             start = 0;
1215             lng[start] = lng[Core::settings.audio.language + 2];
1216         }
1217 
1218         char buf[64];
1219         for (int f = 0; f < COUNT(fmt); f++)
1220             for (int l = start; l < COUNT(lng); l++) {
1221                 strcpy(buf, pre);
1222                 strcat(buf, name);
1223                 strcat(buf, lng[l]);
1224                 strcat(buf, fmt[f]);
1225                 if (Stream::existsContent(buf)) {
1226                     strcpy(name, buf);
1227                     return true;
1228                 }
1229             }
1230 
1231         return false;
1232     }
1233 
getVideoSubs(LevelID id)1234     StringID getVideoSubs(LevelID id) {
1235         switch (id) {
1236         // TR1
1237             case LVL_TR1_TITLE : return isGameEnded ? STR_EMPTY : STR_TR1_SUB_CAFE;
1238             case LVL_TR1_4     : return STR_TR1_SUB_LIFT;
1239             case LVL_TR1_10A   : return STR_TR1_SUB_CANYON;
1240             case LVL_TR1_CUT_4 : return STR_TR1_SUB_PRISON;
1241             default            : return STR_EMPTY;
1242         }
1243     }
1244 
getVideoTrack(LevelID id,Stream::Callback callback,void * userData)1245     bool getVideoTrack(LevelID id, Stream::Callback callback, void *userData) {
1246         char title[32];
1247 
1248         const char *str = NULL;
1249         switch (id) {
1250         // TR1
1251             case LVL_TR1_TITLE : str = isGameEnded ? NULL : "CAFE"; break;
1252             case LVL_TR1_4     : str = "LIFT";   break;
1253             case LVL_TR1_10A   : str = "CANYON"; break;
1254             case LVL_TR1_CUT_4 : str = "PRISON"; break;
1255         // TR2 TODO
1256         // TR3 TODO
1257             default            : return false;
1258         }
1259 
1260         sprintf(title, "track_%s", str);
1261         if (!checkTrack("", title) && !checkTrack("audio/1/", title) && !checkTrack("audio/", title)) {
1262             return false;
1263         }
1264 
1265         new Stream(title, callback, userData);
1266         return true;
1267     }
1268 
getSubs(Version version,int track)1269     StringID getSubs(Version version, int track) {
1270         if ((version & VER_TR1) && (track >= 22 && track <= 56 && track != 24)) {
1271             return StringID(STR_TR1_SUB_22 + (track - 22));
1272         }
1273         // TR2, TR3 TODO
1274         return STR_EMPTY;
1275     }
1276 
checkWebDub(Version version,int track)1277     bool checkWebDub(Version version, int track) {
1278         if (getSubs(version, track) != STR_EMPTY) {
1279             int lang = Core::settings.audio.language + STR_LANG_EN;
1280             return lang == STR_LANG_EN || lang == STR_LANG_DE || lang == STR_LANG_FR || lang == STR_LANG_RU || lang == STR_LANG_JA;
1281         }
1282         return false;
1283     }
1284 
getGameTrack(Version version,int track,Stream::Callback callback,void * userData)1285     void getGameTrack(Version version, int track, Stream::Callback callback, void *userData) {
1286         char title[64];
1287         if (useEasyStart) {
1288             switch (version) {
1289                 case VER_TR1_SAT :
1290                 case VER_TR1_PC  :
1291                 case VER_TR1_PSX :
1292                     sprintf(title, "track_%02d", track);
1293                     if (!checkTrack("", title) && !checkTrack("audio/1/", title) && !checkTrack("audio/", title)) {
1294                         track = remapTrack(version, track);
1295                         sprintf(title, "%03d", track);
1296                         if (!checkTrack("", title) && !checkTrack("audio/1/", title) && !checkTrack("audio/", title)) {
1297                             callback(NULL, userData);
1298                             return;
1299                         }
1300                     }
1301                     break;
1302                 case VER_TR2_PC  :
1303                 case VER_TR2_PSX :
1304                     //if (Stream::existsContent("audio/cdaudio.mp3")) {
1305                     //    callback(Sound::openCDAudioMP3("audio/cdaudio.dat", "audio/cdaudio.mp3", track), userData);
1306                     //    return;
1307                     //}
1308                     track = remapTrack(version, track);
1309                     sprintf(title, "track_%02d", track);
1310                     if (!checkTrack("", title) && !checkTrack("audio/2/", title) && !checkTrack("audio/", title)) {
1311                         callback(NULL, userData);
1312                         return;
1313                     }
1314                     break;
1315                 case VER_TR3_PC  :
1316                 case VER_TR3_PSX :
1317                     callback(Sound::openCDAudioWAD("audio/cdaudio.wad", track), userData);
1318                     return;
1319                 case VER_TR4_PC  :
1320                     strcpy(title, TRACK_LIST_TR4[track]);
1321                     if (!checkTrack("audio/", title)) {
1322                         callback(NULL, userData);
1323                     }
1324                     break;
1325                 default : return;
1326             }
1327         } else {
1328             switch (version) {
1329                 case VER_TR1_SAT :
1330                 case VER_TR1_PC  :
1331                 case VER_TR1_PSX : {
1332                     if (TR::checkWebDub(version, track)) {
1333                         const char *lng[] = { LANG_PREFIXES };
1334                         sprintf(title, "audio/1/track_%02d%s.ogg", track, lng[Core::settings.audio.language]);
1335                     } else {
1336                         if (TR::getSubs(version, track) != STR_EMPTY) {
1337                             sprintf(title, "audio/1/track_%02d_EN.ogg", track);
1338                         } else {
1339                             sprintf(title, "audio/1/track_%02d.ogg", track);
1340                         }
1341                     }
1342                 #ifndef _OS_WEB
1343                     if (Stream::existsContent(title))
1344                         break;
1345                     track = remapTrack(version, track);
1346                     sprintf(title, "audio/1/%03d.ogg", track);
1347                 #endif
1348                     break;
1349                 }
1350                 case VER_TR2_PC  :
1351                 case VER_TR2_PSX :
1352                     track = remapTrack(version, track);
1353                     sprintf(title, "audio/2/track_%02d.ogg", track);
1354                     break;
1355                 case VER_TR3_PC  :
1356                 case VER_TR3_PSX :
1357                     #ifndef _OS_WEB
1358                         callback(Sound::openCDAudioWAD("audio/3/cdaudio.wad", track), userData);
1359                         return;
1360                     #else
1361                         sprintf(title, "audio/3/track_%02d.wav", track);
1362                     #endif
1363                     break;
1364                 default : return;
1365             }
1366         }
1367 
1368         new Stream(title, callback, userData);
1369     }
1370 
getGameScreen(LevelID id)1371     const char* getGameScreen(LevelID id) {
1372         switch (id) {
1373         // TR1
1374             case LVL_TR1_TITLE :
1375                 CHECK_FILE("TITLEH.png");           // Android
1376                 CHECK_FILE("DATA/TITLEH.PCX");      // PC
1377                 CHECK_FILE("DELDATA/AMERTIT.RAW");  // PSX
1378                 CHECK_FILE("DELDATA/JAPTIT.RAW");   // PSX JAP
1379                 CHECK_FILE("BINDATA/USATIT.BIN");   // SEGA
1380                 CHECK_FILE("BINDATA/TITLE1.BIN");   // SEGA
1381                 return "level/1/AMERTIT.PNG";       // WEB
1382             case LVL_TR1_GYM :
1383                 CHECK_FILE("DELDATA/GYMLOAD.RAW");
1384                 CHECK_FILE("BINDATA/GYM224.BIN");
1385                 CHECK_FILE("BINDATA/GYM.BIN");
1386                 return "level/1/GYMLOAD.PNG";
1387             case LVL_TR1_1  :
1388             case LVL_TR1_2  :
1389             case LVL_TR1_3A :
1390             case LVL_TR1_3B :
1391                 CHECK_FILE("DELDATA/AZTECLOA.RAW");
1392                 CHECK_FILE("BINDATA/AZTEC224.BIN");
1393                 CHECK_FILE("BINDATA/AZTEC.BIN");
1394                 return "level/1/AZTECLOA.PNG";
1395             case LVL_TR1_4  :
1396             case LVL_TR1_5  :
1397             case LVL_TR1_6  :
1398             case LVL_TR1_7A :
1399             case LVL_TR1_7B :
1400                 CHECK_FILE("DELDATA/GREEKLOA.RAW");
1401                 CHECK_FILE("BINDATA/GREEK224.BIN");
1402                 CHECK_FILE("BINDATA/GREEK.BIN");
1403                 return "level/1/GREEKLOA.PNG";
1404             case LVL_TR1_8A :
1405             case LVL_TR1_8B :
1406             case LVL_TR1_8C :
1407                 CHECK_FILE("DELDATA/EGYPTLOA.RAW");
1408                 CHECK_FILE("BINDATA/EGYPT224.BIN");
1409                 CHECK_FILE("BINDATA/EGYPT.BIN");
1410                 return "level/1/EGYPTLOA.PNG";
1411             case LVL_TR1_10A :
1412             case LVL_TR1_10B :
1413             case LVL_TR1_10C :
1414                 CHECK_FILE("DELDATA/ATLANLOA.RAW");
1415                 CHECK_FILE("BINDATA/ATLAN224.BIN");
1416                 CHECK_FILE("BINDATA/ATLAN.BIN");
1417                 return "level/1/ATLANLOA.PNG";
1418         // TR2
1419             case LVL_TR2_TITLE :
1420                 CHECK_FILE("TITLE.png");            // Android
1421                 CHECK_FILE("data/TITLE.PCX");       // PC
1422                 CHECK_FILE("pix/title.pcx");        // PC
1423                 CHECK_FILE("PIXUS/TITLEUS.RAW");    // PSX US
1424                 CHECK_FILE("PIXJAP/TITLEJAP.RAW");  // PSX US
1425                 return "level/2/TITLEUS.PNG";       // WEB
1426             case LVL_TR2_ASSAULT :
1427             case LVL_TR2_HOUSE   :
1428                 CHECK_FILE("PIX/MANSION.RAW");
1429                 return "level/2/MANSION.PNG";
1430             case LVL_TR2_WALL     :
1431             case LVL_TR2_EMPRTOMB :
1432             case LVL_TR2_FLOATING :
1433             case LVL_TR2_XIAN     :
1434                 CHECK_FILE("PIX/CHINA.RAW");
1435                 return "level/2/CHINA.PNG";
1436             case LVL_TR2_BOAT   :
1437             case LVL_TR2_VENICE :
1438             case LVL_TR2_OPERA  :
1439                 CHECK_FILE("PIX/VENICE.RAW");
1440                 return "level/2/VENICE.PNG";
1441             case LVL_TR2_RIG      :
1442             case LVL_TR2_PLATFORM :
1443                 CHECK_FILE("PIX/RIG.RAW");
1444                 return "level/2/RIG.PNG";
1445             case LVL_TR2_UNWATER :
1446             case LVL_TR2_KEEL    :
1447             case LVL_TR2_LIVING  :
1448             case LVL_TR2_DECK    :
1449                 CHECK_FILE("PIX/TITAN.RAW");
1450                 return "level/2/TITAN.PNG";
1451             case LVL_TR2_SKIDOO   :
1452             case LVL_TR2_MONASTRY :
1453             case LVL_TR2_CATACOMB :
1454             case LVL_TR2_ICECAVE  :
1455                 CHECK_FILE("PIX/TIBET.RAW");
1456                 return "level/2/TIBET.PNG";
1457         // TR3
1458             case LVL_TR3_TITLE :
1459                 CHECK_FILE("pix/TITLEUK.BMP");      // PC
1460                 CHECK_FILE("PIXUS/TITLEUS.RAW");    // PSX
1461                 CHECK_FILE("PIXJAP/TITLEJAP.RAW");  // PSX
1462                 return "level/3/TITLEUK.PNG";       // WEB
1463             case LVL_TR3_HOUSE  :
1464                 CHECK_FILE("pix/HOUSE.BMP");
1465                 CHECK_FILE("PIX/HOUSE.RAW");
1466                 return "level/3/HOUSE.PNG";
1467             case LVL_TR3_JUNGLE   :
1468             case LVL_TR3_TEMPLE   :
1469             case LVL_TR3_QUADCHAS :
1470             case LVL_TR3_TONYBOSS :
1471                 CHECK_FILE("pix/INDIA.BMP");
1472                 CHECK_FILE("PIX/INDIA.RAW");
1473                 return "level/3/INDIA.PNG";
1474             case LVL_TR3_SHORE   :
1475             case LVL_TR3_CRASH   :
1476             case LVL_TR3_RAPIDS  :
1477             case LVL_TR3_TRIBOSS :
1478                 CHECK_FILE("pix/SOUTHPAC.BMP");
1479                 CHECK_FILE("PIX/SOUTHPAC.RAW");
1480                 return "level/3/SOUTHPAC.PNG";
1481             case LVL_TR3_ROOFS  :
1482             case LVL_TR3_SEWER  :
1483             case LVL_TR3_TOWER  :
1484             case LVL_TR3_OFFICE :
1485             case LVL_TR3_STPAUL :
1486                 CHECK_FILE("pix/LONDON.BMP");
1487                 CHECK_FILE("PIX/LONDON.RAW");
1488                 return "level/3/LONDON.PNG";
1489             case LVL_TR3_NEVADA   :
1490             case LVL_TR3_COMPOUND :
1491             case LVL_TR3_AREA51   :
1492                 CHECK_FILE("pix/NEVADA.BMP");
1493                 CHECK_FILE("PIX/NEVADA.RAW");
1494                 return "level/3/NEVADA.PNG";
1495             case LVL_TR3_ANTARC  :
1496             case LVL_TR3_MINES   :
1497             case LVL_TR3_CITY    :
1498             case LVL_TR3_CHAMBER :
1499                 CHECK_FILE("pix/ANTARC.BMP");
1500                 CHECK_FILE("PIX/ANTARC.RAW");
1501                 return "level/3/ANTARC.PNG";
1502 
1503             default : return NULL;
1504         }
1505     }
1506 
getGameLogo(Version version)1507     const char* getGameLogo(Version version) {
1508         if (version & VER_TR1) {
1509             CHECK_FILE("FMV/CORELOGO.FMV");
1510             CHECK_FILE("FMV/CORE.RPL");
1511             CHECK_FILE("FMV/CORELOGO.CPK");
1512             CHECK_FILE("video/1/CORELOGO.FMV");
1513             CHECK_FILE("video/1/CORE.RPL");
1514         }
1515 
1516         if (version & VER_TR2) {
1517             CHECK_FILE("FMV/LOGO.FMV");
1518             CHECK_FILE("FMV/LOGO.RPL");
1519             CHECK_FILE("video/2/LOGO.FMV");
1520             CHECK_FILE("video/2/LOGO.RPL");
1521         }
1522 
1523         if (version & VER_TR3) {
1524             CHECK_FILE("FMV/LOGO.FMV");
1525             CHECK_FILE("fmv/logo.rpl");
1526             CHECK_FILE("video/3/LOGO.FMV");
1527             CHECK_FILE("video/3/logo.rpl");
1528         }
1529 
1530         return NULL;
1531     }
1532 
getGameVideo(LevelID id)1533     const char* getGameVideo(LevelID id) {
1534         switch (id) {
1535         // TR1
1536             case LVL_TR1_TITLE :
1537                 if (isGameEnded) {
1538                     CHECK_FILE("FMV/END.FMV");
1539                     CHECK_FILE("FMV/END.RPL");
1540                     CHECK_FILE("FMV/END.CPK");
1541                     CHECK_FILE("video/1/END.FMV");
1542                     CHECK_FILE("video/1/END.RPL");
1543                     CHECK_FILE("video/1/END.CPK");
1544                 } else {
1545                     CHECK_FILE("FMV/CAFE.FMV");
1546                     CHECK_FILE("FMV/CAFE.RPL");
1547                     CHECK_FILE("FMV/CAFE.CPK");
1548                     CHECK_FILE("video/1/CAFE.FMV");
1549                     CHECK_FILE("video/1/CAFE.RPL");
1550                     CHECK_FILE("video/1/CAFE.CPK");
1551                 }
1552                 break;
1553             case LVL_TR1_GYM :
1554                 CHECK_FILE("FMV/MANSION.FMV");
1555                 CHECK_FILE("FMV/MANSION.RPL");
1556                 CHECK_FILE("FMV/MANSION.CPK");
1557                 CHECK_FILE("video/1/MANSION.FMV");
1558                 CHECK_FILE("video/1/MANSION.RPL");
1559                 CHECK_FILE("video/1/MANSION.CPK");
1560                 break;
1561             case LVL_TR1_1 :
1562                 CHECK_FILE("FMV/SNOW.FMV");
1563                 CHECK_FILE("FMV/SNOW.RPL");
1564                 CHECK_FILE("FMV/SNOW.CPK");
1565                 CHECK_FILE("video/1/SNOW.FMV");
1566                 CHECK_FILE("video/1/SNOW.RPL");
1567                 CHECK_FILE("video/1/SNOW.CPK");
1568                 break;
1569             case LVL_TR1_4 :
1570                 CHECK_FILE("FMV/LIFT.FMV");
1571                 CHECK_FILE("FMV/LIFT.RPL");
1572                 CHECK_FILE("FMV/LIFT.CPK");
1573                 CHECK_FILE("video/1/LIFT.FMV");
1574                 CHECK_FILE("video/1/LIFT.RPL");
1575                 CHECK_FILE("video/1/LIFT.CPK");
1576                 break;
1577             case LVL_TR1_8A :
1578                 CHECK_FILE("FMV/VISION.FMV");
1579                 CHECK_FILE("FMV/VISION.RPL");
1580                 CHECK_FILE("FMV/VISION.CPK");
1581                 CHECK_FILE("video/1/VISION.FMV");
1582                 CHECK_FILE("video/1/VISION.RPL");
1583                 CHECK_FILE("video/1/VISION.CPK");
1584                 break;
1585             case LVL_TR1_10A :
1586                 CHECK_FILE("FMV/CANYON.FMV");
1587                 CHECK_FILE("FMV/CANYON.RPL");
1588                 CHECK_FILE("FMV/CANYON.CPK");
1589                 CHECK_FILE("video/1/CANYON.FMV");
1590                 CHECK_FILE("video/1/CANYON.RPL");
1591                 CHECK_FILE("video/1/CANYON.CPK");
1592                 break;
1593             case LVL_TR1_10B :
1594                 CHECK_FILE("FMV/PYRAMID.FMV");
1595                 CHECK_FILE("FMV/PYRAMID.RPL");
1596                 CHECK_FILE("FMV/PYRAMID.CPK");
1597                 CHECK_FILE("video/1/PYRAMID.FMV");
1598                 CHECK_FILE("video/1/PYRAMID.RPL");
1599                 CHECK_FILE("video/1/PYRAMID.CPK");
1600                 break;
1601             case LVL_TR1_CUT_4 :
1602                 CHECK_FILE("FMV/PRISON.FMV");
1603                 CHECK_FILE("FMV/PRISON.RPL");
1604                 CHECK_FILE("FMV/PRISON.CPK");
1605                 CHECK_FILE("video/1/PRISON.FMV");
1606                 CHECK_FILE("video/1/PRISON.RPL");
1607                 CHECK_FILE("video/1/PRISON.CPK");
1608                 break;
1609             case LVL_TR1_EGYPT :
1610                 CHECK_FILE("FMV/END.FMV");
1611                 CHECK_FILE("FMV/END.RPL");
1612                 CHECK_FILE("FMV/END.CPK");
1613                 CHECK_FILE("video/1/END.FMV");
1614                 CHECK_FILE("video/1/END.RPL");
1615                 CHECK_FILE("video/1/END.CPK");
1616                 break;
1617         // TR2
1618             case LVL_TR2_TITLE    :
1619                 CHECK_FILE("FMV/ANCIENT.FMV");
1620                 CHECK_FILE("fmv/ANCIENT.RPL");
1621                 CHECK_FILE("video/2/ANCIENT.FMV");
1622                 CHECK_FILE("video/2/ANCIENT.RPL");
1623                 break;
1624             case LVL_TR2_WALL     :
1625                 CHECK_FILE("FMV/MODERN.FMV");
1626                 CHECK_FILE("fmv/MODERN.RPL");
1627                 CHECK_FILE("video/2/MODERN.FMV");
1628                 CHECK_FILE("video/2/MODERN.RPL");
1629                 break;
1630             case LVL_TR2_RIG      :
1631                 CHECK_FILE("FMV/LANDING.FMV");
1632                 CHECK_FILE("fmv/LANDING.RPL");
1633                 CHECK_FILE("video/2/LANDING.FMV");
1634                 CHECK_FILE("video/2/LANDING.RPL");
1635                 break;
1636             case LVL_TR2_UNWATER  :
1637                 CHECK_FILE("FMV/MS.FMV");
1638                 CHECK_FILE("fmv/MS.RPL");
1639                 CHECK_FILE("video/2/MS.FMV");
1640                 CHECK_FILE("video/2/MS.RPL");
1641                 break;
1642             case LVL_TR2_SKIDOO   :
1643                 CHECK_FILE("FMV/CRASH.FMV");
1644                 CHECK_FILE("fmv/CRASH.RPL");
1645                 CHECK_FILE("video/2/CRASH.FMV");
1646                 CHECK_FILE("video/2/CRASH.RPL");
1647                 break;
1648             case LVL_TR2_EMPRTOMB :
1649                 CHECK_FILE("FMV/JEEP.FMV");
1650                 CHECK_FILE("fmv/JEEP.RPL");
1651                 CHECK_FILE("video/2/JEEP.FMV");
1652                 CHECK_FILE("video/2/JEEP.RPL");
1653                 break;
1654             case LVL_TR2_HOUSE    :
1655                 CHECK_FILE("FMV/END.FMV");
1656                 CHECK_FILE("fmv/END.RPL");
1657                 CHECK_FILE("video/2/END.FMV");
1658                 CHECK_FILE("video/2/END.RPL");
1659                 break;
1660         // TR3
1661             case LVL_TR3_TITLE :
1662                 if (isGameEnded) {
1663                     CHECK_FILE("FMV/END.FMV");
1664                     CHECK_FILE("fmv/Endgame.rpl");
1665                     CHECK_FILE("video/3/END.FMV");
1666                     CHECK_FILE("video/3/Endgame.rpl");
1667                 } else {
1668                     CHECK_FILE("FMV/INTRO.FMV");
1669                     CHECK_FILE("fmv/Intr_Eng.rpl");
1670                     CHECK_FILE("video/3/INTRO.FMV");
1671                     CHECK_FILE("video/3/Intr_Eng.rpl");
1672                 }
1673                 break;
1674             case LVL_TR3_SHORE :
1675                 CHECK_FILE("FMV/LAGOON.FMV");
1676                 CHECK_FILE("fmv/Sail_Eng.rpl");
1677                 CHECK_FILE("video/3/LAGOON.FMV");
1678                 CHECK_FILE("video/3/Sail_Eng.rpl");
1679                 break;
1680             case LVL_TR3_ANTARC :
1681                 CHECK_FILE("FMV/HUEY.FMV");
1682                 CHECK_FILE("fmv/Crsh_Eng.rpl");
1683                 CHECK_FILE("video/3/HUEY.FMV");
1684                 CHECK_FILE("video/3/Crsh_Eng.rpl");
1685                 break;
1686             case LVL_TR3_STPAUL :
1687                 CHECK_FILE("FMV/END.FMV");
1688                 CHECK_FILE("fmv/Endgame.rpl");
1689                 CHECK_FILE("video/3/END.FMV");
1690                 CHECK_FILE("video/3/Endgame.rpl");
1691                 break;
1692             default : ;
1693         }
1694         return NULL;
1695     }
1696 
1697     #define FOG_DIST    (1.0f / (18 * 1024))
1698     #define FOG_NONE    vec4(0.0f,  0.0f, 0.0f,  0.0f)
1699     #define FOG_BLACK   vec4(0.0f,  0.0f, 0.0f,  FOG_DIST)
1700     #define FOG_SANDY   vec4(0.2f,  0.1f, 0.0f,  FOG_DIST)
1701     #define FOG_GREEN   vec4(0.0f,  0.1f, 0.0f,  FOG_DIST)
1702     #define FOG_RED     vec4(0.2f,  0.0f, 0.0f,  FOG_DIST)
1703     #define FOG_MIST    vec4(0.25f, 0.2f, 0.15f, FOG_DIST)
1704 
getFogParams(LevelID id)1705     vec4 getFogParams(LevelID id) {
1706         switch (id) {
1707             case LVL_TR1_1     :
1708             case LVL_TR1_2     : return FOG_BLACK;
1709             case LVL_TR1_3A    : return FOG_MIST;
1710             case LVL_TR1_3B    :
1711             case LVL_TR1_CUT_1 : return FOG_BLACK;
1712             case LVL_TR1_4     :
1713             case LVL_TR1_5     :
1714             case LVL_TR1_6     : return FOG_SANDY;
1715             case LVL_TR1_7A    :
1716             case LVL_TR1_7B    :
1717             case LVL_TR1_CUT_2 : return FOG_GREEN;
1718             case LVL_TR1_8A    :
1719             case LVL_TR1_8B    :
1720             case LVL_TR1_8C    : return FOG_SANDY;
1721             case LVL_TR1_10A   : return FOG_BLACK;
1722             case LVL_TR1_CUT_3 :
1723             case LVL_TR1_10B   :
1724             case LVL_TR1_CUT_4 :
1725             case LVL_TR1_10C   : return FOG_RED;
1726             case LVL_TR1_EGYPT :
1727             case LVL_TR1_CAT   :
1728             case LVL_TR1_END   :
1729             case LVL_TR1_END2  : return FOG_SANDY;
1730             default            : return FOG_BLACK;
1731         }
1732     }
1733 
1734     struct SkyParams {
1735         vec4 skyDownColor;
1736         vec4 skyUpColor;
1737         vec4 sunDirSize;
1738         vec4 sunColorGlare;
1739         vec4 cloudDownColor;
1740         vec4 cloudUpColor;
1741         vec3 wind;
1742     };
1743 
1744     #define CLOUD_UP    vec3()
1745     #define CLOUD_DOWN  vec3()
1746 
getSkyParams(LevelID id,SkyParams & params)1747     bool getSkyParams(LevelID id, SkyParams &params) {
1748         switch (id) {
1749             case LVL_TR1_3A :
1750                 params.skyDownColor    = vec4(0.8f, 0.8f, 0.7f, 1.0f);
1751                 params.skyUpColor      = vec4(0.3f, 0.4f, 0.5f, 1.0f);
1752                 params.sunDirSize      = vec4(vec3(1.0f, 0.75f, -1.0f).normal(), 0.0025f);
1753                 params.sunColorGlare   = vec4(0.8f, 0.4f, 0.1f, 4.0f);
1754                 params.cloudDownColor  = vec4(0.35f, 0.4f, 0.45f, 1.0f);
1755                 params.cloudUpColor    = vec4(1.1f, 1.045f, 0.88f, 1.0f);
1756                 params.wind            = vec3(0.01f, -0.005f, 0.005f);
1757                 break;
1758             case LVL_TR1_5 :
1759                 params.skyDownColor    = vec4(0.15f, 0.05f, 0.0f, 1.0f);
1760                 params.skyUpColor      = vec4(0.3f, 0.2f, 0.1f, 1.0f);
1761                 params.sunDirSize      = vec4(vec3(-1.0f, 0.8f, -1.0f).normal(), 0.0015f);
1762                 params.sunColorGlare   = vec4(0.7f, 0.7f, 0.6f, 256.0f);
1763                 params.cloudDownColor  = vec4(0.2f, 0.1f, 0.0f, 1.0f);
1764                 params.cloudUpColor    = vec4(0.5f, 0.5f, 0.4f, 1.0f);
1765                 params.wind            = vec3(0.01f, -0.005f, 0.005f);
1766                 break;
1767             case LVL_TR3_HOUSE : // test
1768                 params.skyDownColor    = vec4(0.8f, 0.8f, 0.7f, 1.0f);
1769                 params.skyUpColor      = vec4(0.3f, 0.4f, 0.5f, 1.0f);
1770                 params.sunDirSize      = vec4(vec3(1.0f, 0.75f, -1.0f).normal(), 0.0025f);
1771                 params.sunColorGlare   = vec4(0.8f, 0.4f, 0.1f, 4.0f);
1772                 params.cloudDownColor  = vec4(0.35f, 0.4f, 0.45f, 1.0f);
1773                 params.cloudUpColor    = vec4(1.1f, 1.045f, 0.88f, 1.0f);
1774                 params.wind            = vec3(0.01f, -0.005f, 0.005f);
1775                 break;
1776             default : return false;
1777         }
1778         return true;
1779     }
1780 }
1781 
1782 #undef CHECK_FILE
1783 
1784 #endif
1785