Explorar el Código

Can read TR3 Script

Thomas Buck hace 10 años
padre
commit
a3adea1549
Se han modificado 4 ficheros con 76 adiciones y 49 borrados
  1. 1
    0
      ChangeLog.md
  2. 6
    4
      include/Script.h
  3. 62
    45
      src/Script.cpp
  4. 7
    0
      test/Script.cpp

+ 1
- 0
ChangeLog.md Ver fichero

@@ -4,6 +4,7 @@
4 4
 
5 5
     [ 20140807 ]
6 6
     * Script parser successfully loading level scripts
7
+    * Can also read TR3 script now
7 8
 
8 9
     [ 20140806 ]
9 10
     * Improved Script reader and its Unit Test

+ 6
- 4
include/Script.h Ver fichero

@@ -30,7 +30,7 @@ public:
30 30
     } ScriptLanguage;
31 31
 
32 32
     typedef enum {
33
-        OP_PICTURE        = 0,  //!< Unused in TR2. Or PSX?
33
+        OP_PICTURE        = 0,  //!< Unused in TR2. Or PSX? Used in TR3.
34 34
         OP_PSX_TRACK      = 1,  //!< Does not compile. PSX?
35 35
         OP_PSX_FMV        = 2,  //!< Does not compile. PSX?
36 36
         OP_FMV            = 3,  //!< Display FMV
@@ -42,10 +42,10 @@ public:
42 42
         OP_END            = 9,  //!< Closes script sequence
43 43
         OP_TRACK          = 10, //!< Play soundtrack (precedes level opcode)
44 44
         OP_SUNSET         = 11, //!< Unknown, nothing changes in TR2.
45
-        OP_LOAD_PIC       = 12, //!< Does not compile. PSX or TR3?
45
+        OP_LOAD_PIC       = 12, //!< Does not compile. PSX? Used in TR3.
46 46
         OP_DEADLY_WATER   = 13, //!< Unknown, nothing changes in TR2.
47 47
         OP_REMOVE_WEAPONS = 14, //!< Start level without weapons
48
-        OP_GAMECOMPLETE   = 15, //!< End of game. Show stats, start credits sequence, music ID 52.
48
+        OP_GAMECOMPLETE   = 15, //!< End of game. Show stats, start credits sequence, music ID 52 in TR2.
49 49
         OP_CUTANGLE       = 16, //!< Match N-S orientation of Room and animated characters.
50 50
         OP_NOFLOOR        = 17, //!< Lara dies when her feet reach given depth.
51 51
         OP_STARTINV       = 18, //!< Items given to Lara at level start (+1000), or at all secrets found (+0)
@@ -58,6 +58,7 @@ public:
58 58
 
59 59
     // Items for all-secrets-found go from 0 to 26,
60 60
     // for start-inventory add 1000, so 1000 - 1026
61
+    // Atleast in TR2
61 62
     typedef enum {
62 63
         OP_WEAPON_PISTOLS     = 0,  //!< Add standard pistols (2)
63 64
         OP_WEAPON_SHOTGUN     = 1,  //!< Add shotgun (1)
@@ -138,6 +139,7 @@ private:
138 139
     } ScriptFlag;
139 140
 
140 141
     void readStringPackage(BinaryFile &f, std::vector<std::string> &v, unsigned int n);
142
+    void readScriptPackage(BinaryFile &f, std::vector<std::vector<uint16_t>> &v, unsigned int n);
141 143
 
142 144
     const bool opcodeHasOperand[OP_UNKNOWN] {
143 145
         true, true, true, true, true, true,
@@ -180,7 +182,7 @@ private:
180 182
     std::vector<std::string> cutsceneFilenames; // numCutscenes
181 183
     std::vector<std::vector<uint16_t>> script; // numLevels + 1
182 184
     uint16_t numGameStrings;
183
-    std::vector<std::string> gameStrings; // numGameStrings, 89
185
+    std::vector<std::string> gameStrings; // numGameStrings
184 186
     std::vector<std::string> pcStrings; // 41
185 187
     std::vector<std::vector<std::string>> puzzles; // 4 * numLevels
186 188
     std::vector<std::vector<std::string>> pickups; // 2 * numLevels

+ 62
- 45
src/Script.cpp Ver fichero

@@ -35,7 +35,7 @@ int Script::load(const char *file) {
35 35
     titleReplace = f.read32();
36 36
     onDeathDemoMode = f.readU32();
37 37
     onDeathInGame = f.readU32();
38
-    noInputTime = f.readU32();
38
+    noInputTime = f.readU32(); // Scaled *100 in TR3
39 39
     onDemoInterrupt = f.readU32();
40 40
     onDemoEnd = f.readU32();
41 41
 
@@ -61,7 +61,7 @@ int Script::load(const char *file) {
61 61
 
62 62
     cypherCode = f.readU8();
63 63
     language = f.readU8();
64
-    secretTrack = f.readU16();
64
+    secretTrack = f.readU16(); // Zero in TR3, Part of filler or real number?
65 65
 
66 66
     // Filler 4 (4 bytes)
67 67
     f.seek(f.tell() + 4);
@@ -74,51 +74,10 @@ int Script::load(const char *file) {
74 74
     readStringPackage(f, levelFilenames, numLevels);
75 75
     readStringPackage(f, cutsceneFilenames, numCutscenes);
76 76
 
77
-    // Script Package
78
-    uint16_t *offset = new uint16_t[numLevels + 1];
79
-    for (unsigned int i = 0; i < (numLevels + 1); i++) {
80
-        offset[i] = f.readU16();
81
-        assertEqual(offset[i] % 2, 0);
82
-    }
83
-
84
-    uint16_t numBytes = f.readU16() + 6; // Offset TR2 specific?!
85
-    assertEqual(numBytes % 2, 0); // 16 bit opcodes and operands
86
-
87
-    uint16_t *list = new uint16_t[numBytes / 2];
88
-    for (uint16_t i = 0; i < (numBytes / 2); i++) {
89
-        list[i] = f.readU16();
90
-    }
91
-
92
-    for (unsigned int i = 0; i < (numLevels + 1); i++) {
93
-        unsigned int end = offset[i] / 2;
94
-
95
-        bool readingOperand = false;
96
-        while (readingOperand || (list[end] != OP_END)) {
97
-            if (readingOperand) {
98
-                readingOperand = false;
99
-                end++;
100
-            } else {
101
-                if (opcodeHasOperand[list[end]]) {
102
-                    readingOperand = true;
103
-                }
104
-                end++;
105
-            }
106
-        }
107
-        end++;
77
+    // Level Scripts
78
+    readScriptPackage(f, script, numLevels + 1);
108 79
 
109
-        std::vector<uint16_t> tmp;
110
-        for (unsigned int a = (offset[i] / 2); a < end; a++)
111
-            tmp.push_back(list[a]);
112
-
113
-        script.push_back(tmp);
114
-    }
115
-
116
-    delete [] list;
117
-    delete [] offset;
118
-
119
-    // Engine expects 89 game strings!
120 80
     numGameStrings = f.readU16();
121
-    assertEqual(numGameStrings, 89);
122 81
 
123 82
     // More strings...
124 83
     readStringPackage(f, gameStrings, numGameStrings);
@@ -161,6 +120,64 @@ void Script::readStringPackage(BinaryFile &f, std::vector<std::string> &v, unsig
161 120
     delete [] offset;
162 121
 }
163 122
 
123
+void Script::readScriptPackage(BinaryFile &f, std::vector<std::vector<uint16_t>> &v, unsigned int n) {
124
+    uint16_t *offset = new uint16_t[n];
125
+    for (unsigned int i = 0; i < n; i++) {
126
+        offset[i] = f.readU16();
127
+        assertEqual(offset[i] % 2, 0);
128
+    }
129
+
130
+    uint16_t numBytes = f.readU16();
131
+    assertEqual(numBytes % 2, 0); // 16 bit opcodes and operands
132
+
133
+    // Only TR2, not TR3, has 6 "filler bytes" hex 13 00 14 00 15 00 here
134
+    // We need to skip these
135
+    uint16_t hack1 = f.readU16();
136
+    uint16_t hack2 = f.readU16();
137
+    uint16_t hack3 = f.readU16();
138
+    uint16_t hackStart = 0;
139
+    uint16_t *list = new uint16_t[(numBytes + 6) / 2];
140
+    if ((hack1 == 19) && (hack2 == 20) && (hack3 == 21)) {
141
+        numBytes += 6;
142
+    } else {
143
+        list[0] = hack1;
144
+        list[1] = hack2;
145
+        list[2] = hack3;
146
+        hackStart = 3;
147
+    }
148
+
149
+    for (uint16_t i = hackStart; i < (numBytes / 2); i++) {
150
+        list[i] = f.readU16();
151
+    }
152
+
153
+    for (unsigned int i = 0; i < n; i++) {
154
+        unsigned int end = offset[i] / 2;
155
+
156
+        bool readingOperand = false;
157
+        while (readingOperand || (list[end] != OP_END)) {
158
+            if (readingOperand) {
159
+                readingOperand = false;
160
+                end++;
161
+            } else {
162
+                if (opcodeHasOperand[list[end]]) {
163
+                    readingOperand = true;
164
+                }
165
+                end++;
166
+            }
167
+        }
168
+        end++;
169
+
170
+        std::vector<uint16_t> tmp;
171
+        for (unsigned int a = (offset[i] / 2); a < end; a++)
172
+            tmp.push_back(list[a]);
173
+
174
+        v.push_back(tmp);
175
+    }
176
+
177
+    delete [] list;
178
+    delete [] offset;
179
+}
180
+
164 181
 unsigned int Script::levelCount() {
165 182
     return numLevels;
166 183
 }

+ 7
- 0
test/Script.cpp Ver fichero

@@ -106,6 +106,13 @@ int main(int argc, char *argv[]) {
106 106
     int error = test(f, !((argc > 1) && (argv[1][0] == 's')));
107 107
     delete [] f;
108 108
 
109
+    if (error != 0)
110
+        return error;
111
+
112
+    f = fullPath("~/.OpenRaider/paks/tr3/TOMBPC.DAT", 0);
113
+    error = test(f, !((argc > 1) && (argv[1][0] == 's')));
114
+    delete [] f;
115
+
109 116
     return error;
110 117
 }
111 118
 

Loading…
Cancelar
Guardar