1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "common/debug-channels.h"
24 #include "common/file.h"
25 #include "common/textconsole.h"
26
27 #include "agos/agos.h"
28 #include "agos/intern.h"
29 #include "agos/sound.h"
30
31 namespace AGOS {
32
33 // Script opcodes to load into memory
34 static const char *const opcodeArgTable_elvira1[300] = {
35 "I ", "I ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "F ", "F ", "FN ",
36 "FN ", "FN ", "FN ", "FF ", "FF ", "FF ", "FF ", "II ", "II ", "a ", "a ", "n ", "n ", "p ",
37 "N ", "I ", "I ", "I ", "I ", "IN ", "IB ", "IB ", "II ", "IB ", "N ", " ", " ", " ", "I ",
38 "I ","I ","I ", "I ","I ","I ", "II ","II ","II ","II ","IBF ", "FIB ", "FF ", "N ", "NI ",
39 "IF ", "F ", "F ", "IB ", "IB ", "FN ", "FN ", "FN ", "FF ", "FF ", "FN ", "FN ", "FF ", "FF ",
40 "FN ", "FF ", "FN ", "F ", "I ", "IN ", "IN ", "IB ", "IB ", "IB ", "IB ", "II ", "I ", "I ",
41 "IN ", "T ", "F ", " ", "T ", "T ", "I ", "I ", " ", " ", "T ", " ", " ", " ", " ", " ", "T ",
42 " ", "N ", "INN ", "II ", "II ", "ITN ", "ITIN ", "ITIN ", "I3 ", "IN ", "I ", "I ", "Ivnn ",
43 "vnn ", "Ivnn ", "NN ", "IT ", "INN ", " ", "N ", "N ", "N ", "T ", "v ", " ", " ", " ", " ",
44 "FN ", "I ", "TN ", "IT ", "II ", "I ", " ", "N ", "I ", " ", "I ", "NI ", "I ", "I ", "T ",
45 "I ", "I ", "N ", "N ", " ", "N ", "IF ", "IF ", "IF ", "IF ", "IF ", "IF ", "T ", "IB ",
46 "IB ", "IB ", "I ", " ", "vnnN ", "Ivnn ", "T ", "T ", "T ", "IF ", " ", " ", " ", "Ivnn ",
47 "IF ", "INI ", "INN ", "IN ", "II ", "IFF ", "IIF ", "I ", "II ", "I ", "I ", "IN ", "IN ",
48 "II ", "II ", "II ", "II ", "IIN ", "IIN ", "IN ", "II ", "IN ", "IN ", "T ", "vanpan ",
49 "vIpI ", "T ", "T ", " ", " ", "IN ", "IN ", "IN ", "IN ", "N ", "INTTT ", "ITTT ",
50 "ITTT ", "I ", "I ", "IN ", "I ", " ", "F ", "NN ", "INN ", "INN ", "INNN ", "TF ", "NN ",
51 "N ", "NNNNN ", "N ", " ", "NNNNNNN ", "N ", " ", "N ", "NN ", "N ", "NNNNNIN ", "N ", "N ",
52 "N ", "NNN ", "NNNN ", "INNN ", "IN ", "IN ", "TT ", "I ", "I ", "I ", "TTT ", "IN ", "IN ",
53 "FN ", "FN ", "FN ", "N ", "N ", "N ", "NI ", " ", " ", "N ", "I ", "INN ", "NN ", "N ",
54 "N ", "Nan ", "NN ", " ", " ", " ", " ", " ", " ", " ", "IF ", "N ", " ", " ", " ", "II ",
55 " ", "NI ","N ",
56 };
57
58 static const char *const opcodeArgTable_elvira2[256] = {
59 " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
60 "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
61 "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
62 "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
63 "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "I ", "I ", " ", "T ", " ", " ",
64 "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
65 "IIB ", "T ", "T ", "T ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NBNNN ", "N ",
66 " ", "BNNNNNN ", "B ", " ", "B ", "B ", "N ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
67 "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
68 "NN ", "N ", "N ", "Ban ", "BB ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ", "N ",
69 "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ", "B ",
70 "IBB ", "IBN ", "IB ", "B ", " ", "TB ", "TB ", "I ", "N ", "B ", "INB ", "INB ", "INB ", "INB ",
71 "INB ", "INB ", "INB ", "N ", " ", "INBB ", "B ", "B ", "Ian ", "B ", "B ", "B ", "B ", "T ",
72 "T ", "B ", " ", "I ", " ", " "
73 };
74
75 static const char *const opcodeArgTable_waxworks[256] = {
76 " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
77 "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
78 "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
79 "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
80 "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "NNNNNB ", "BT ", "BT ", "T ", " ", "B ",
81 "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
82 "IIB ", "T ", "T ", "T ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NBNNN ", "N ",
83 " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
84 "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
85 "NN ", "N ", "N ", "Ban ", "BB ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ", "N ",
86 "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ", "B ",
87 "IBB ", "IBN ", "IB ", "B ", " ", "TB ", "TB ", "I ", "N ", "B ", "INB ", "INB ", "INB ", "INB ",
88 "INB ", "INB ", "INB ", "N ", " ", "INBB ", "B ", "B ", "Ian ", "B ", "B ", "B ", "B ", "T ",
89 "T ", "B ", " ", "I ", " ", " "
90 };
91
92 static const char *const opcodeArgTable_simon1talkie[256] = {
93 " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
94 "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
95 "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
96 "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
97 "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "NNNNNB ", "BT ", "BTS ", "T ", " ", "B ",
98 "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
99 "IIB ", "T ", " ", " ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NBNNN ", "N ",
100 " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
101 "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
102 "NN ", "N ", "N ", "Ban ", "BB ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ", "N ",
103 "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ", "B ",
104 "IBB ", "IBN ", "IB ", "B ", "BNBN ", "BBTS ", "N ", " ", "Ian ", "B ", "B ", "B ", "B ", "T ",
105 "T ", "B ", " ", "I ", " ", " ", "BBI ", "NNBB ", "BBB ", " ", " ", " ", " ", "N ", "N ", " ",
106 " ",
107 };
108
109 static const char *const opcodeArgTable_simon1dos[256] = {
110 " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
111 "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
112 "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
113 "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
114 "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "NNNNNB ", "BT ", "BT ", "T ", " ", "B ",
115 "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
116 "IIB ", "T ", " ", " ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NBNNN ", "N ",
117 " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
118 "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
119 "NN ", "N ", "N ", "Ban ", "BB ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ", "N ",
120 "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ", "B ",
121 "IBB ", "IBN ", "IB ", "B ", "BNBN ", "BBT ", "N ", " ", "Ian ", "B ", "B ", "B ", "B ", "T ",
122 "T ", "B ", " ", "I ", " ", " ", "BBI ", "NNBB ", "BBB ", " ", " ", " ", " ", "N ", "N ", " ",
123 " ",
124 };
125
126 static const char *const opcodeArgTable_simon2talkie[256] = {
127 " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
128 "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
129 "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
130 "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
131 "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "NNNNNB ", "BT ", "BTS ", "T ", " ", "B ",
132 "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
133 "IIB ", "T ", " ", " ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NNBNNN ", "NN ",
134 " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
135 "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
136 "NNB ", "N ", "N ", "Ban ", "BB ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ",
137 "N ", "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ",
138 "B ", "IBB ", "IBN ", "IB ", "B ", "BNBN ", "BBTS ", "N ", " ", "Ian ", "B ", "B ", "B ", "B ",
139 "T ", "T ", "B ", " ", "I ", " ", " ", "BBI ", "NNBB ", "BBB ", " ", " ", " ", " ", "N ", "N ",
140 " ", " ", "BT ", " ", "B "
141 };
142
143 static const char *const opcodeArgTable_simon2dos[256] = {
144 " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
145 "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
146 "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
147 "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
148 "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "NNNNNB ", "BT ", "BT ", "T ", " ", "B ",
149 "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
150 "IIB ", "T ", " ", " ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NNBNNN ", "NN ",
151 " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
152 "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
153 "NNB ", "N ", "N ", "Ban ", "BB ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ",
154 "N ", "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ",
155 "B ", "IBB ", "IBN ", "IB ", "B ", "BNBN ", "BBT ", "N ", " ", "Ian ", "B ", "B ", "B ", "B ",
156 "T ", "T ", "B ", " ", "I ", " ", " ", "BBI ", "NNBB ", "BBB ", " ", " ", " ", " ", "N ", "N ",
157 " ", " ", "BT ", " ", "B "
158 };
159
160 static const char *const opcodeArgTable_feeblefiles[256] = {
161 " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
162 "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
163 "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
164 "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
165 "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "NNNNNB ", "BT ", "BTS ", "T ", " ", "B ",
166 "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
167 "IIB ", "T ", " ", " ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NNBNNN ", "NN ",
168 " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
169 "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
170 "NNB ", "N ", "N ", "Ban ", " ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ",
171 "N ", "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ",
172 "B ", "IBB ", "IBN ", "IB ", "B ", "BNNN ", "BBTS ", "N ", " ", "Ian ", "B ", "B ", "B ", "B ",
173 "T ", "N ", " ", " ", "I ", " ", " ", "BBI ", "NNBB ", "BBB ", " ", " ", "T ", " ", "N ", "N ",
174 " ", " ", "BT ", " ", "B ", " ", "BBBB ", " ", " ", "BBBB ", "B ", "B ", "B ", "B "
175 };
176
177 static const char *const opcodeArgTable_puzzlepack[256] = {
178 " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "N ", "N ", "NN ", "NN ",
179 "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
180 "II ", "I ", "I ", "II ", "II ", "IBN ", "NIB ", "NN ", "B ", "BI ", "IN ", "N ", "N ", "NN ",
181 "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "B ", "I ", "IB ",
182 "IB ", "II ", "I ", "I ", "IN ", "N ", "T ", "T ", "NNNNNB ", "BTNN ", "BTS ", "T ", " ", "B ",
183 "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
184 "IIB ", "T ", " ", " ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NNBNNN ", "NN ",
185 " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
186 "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
187 "NNB ", "N ", "N ", "Ban ", " ", " ", " ", " ", " ", "IN ", "B ", " ", "II ", " ", "BI ",
188 "N ", "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "N ", "N ", "N ",
189 "N ", "IBN ", "IBN ", "IN ", "B ", "BNNN ", "BBTS ", "N ", " ", "Ian ", "B ", "B ", "B ", "B ",
190 "T ", "N ", " ", " ", "I ", " ", " ", "BBI ", "NNBB ", "BBB ", " ", " ", "T ", " ", "N ", "N ",
191 " ", " ", "BT ", " ", "B ", " ", "BBBB ", " ", " ", "BBBB ", "B ", "B ", "B ", "B "
192 };
193
getSubroutineByID(uint subroutineId)194 Subroutine *AGOSEngine::getSubroutineByID(uint subroutineId) {
195 Subroutine *cur;
196
197 for (cur = _subroutineList; cur; cur = cur->next) {
198 if (cur->id == subroutineId)
199 return cur;
200 }
201
202 if (loadXTablesIntoMem(subroutineId)) {
203 for (cur = _subroutineList; cur; cur = cur->next) {
204 if (cur->id == subroutineId)
205 return cur;
206 }
207 }
208
209 if (loadTablesIntoMem(subroutineId)) {
210 for (cur = _subroutineList; cur; cur = cur->next) {
211 if (cur->id == subroutineId)
212 return cur;
213 }
214 }
215
216 debug(0,"getSubroutineByID: subroutine %d not found", subroutineId);
217 return NULL;
218 }
219
alignTableMem()220 void AGOSEngine::alignTableMem() {
221 if (!IS_ALIGNED(_tablesHeapPtr, 4)) {
222 _tablesHeapPtr += 2;
223 _tablesHeapCurPos += 2;
224 }
225 }
226
allocateTable(uint size)227 void *AGOSEngine::allocateTable(uint size) {
228 byte *org = _tablesHeapPtr;
229
230 size = (size + 1) & ~1;
231
232 _tablesHeapPtr += size;
233 _tablesHeapCurPos += size;
234
235 if (_tablesHeapCurPos > _tablesHeapSize)
236 error("Tablesheap overflow");
237
238 return org;
239 }
240
allocTablesHeap()241 void AGOSEngine::allocTablesHeap() {
242 _tablesHeapSize = _tableMemSize;
243 _tablesHeapCurPos = 0;
244 _tablesHeapPtr = (byte *)calloc(_tableMemSize, 1);
245 if (!_tablesHeapPtr)
246 error("Out Of Memory - Tables");
247 }
248
endCutscene()249 void AGOSEngine::endCutscene() {
250 Subroutine *sub;
251
252 _sound->stopVoice();
253
254 sub = getSubroutineByID(170);
255 if (sub != NULL)
256 startSubroutineEx(sub);
257
258 _runScriptReturn1 = true;
259 }
260
openTablesFile(const char * filename)261 Common::SeekableReadStream *AGOSEngine::openTablesFile(const char *filename) {
262 if (getFeatures() & GF_OLD_BUNDLE)
263 return openTablesFile_simon1(filename);
264 else
265 return openTablesFile_gme(filename);
266 }
267
openTablesFile_simon1(const char * filename)268 Common::SeekableReadStream *AGOSEngine::openTablesFile_simon1(const char *filename) {
269 Common::File *in = new Common::File();
270 if (!in->open(filename))
271 error("openTablesFile: Can't open '%s'", filename);
272 return in;
273 }
274
openTablesFile_gme(const char * filename)275 Common::SeekableReadStream *AGOSEngine::openTablesFile_gme(const char *filename) {
276 uint res;
277 uint32 offs;
278
279 res = atoi(filename + 6) + _tableIndexBase - 1;
280 offs = _gameOffsetsPtr[res];
281
282 _gameFile->seek(offs, SEEK_SET);
283 return _gameFile;
284 }
285
loadTablesIntoMem(uint16 subrId)286 bool AGOSEngine::loadTablesIntoMem(uint16 subrId) {
287 byte *p;
288 uint16 min_num, max_num, file_num;
289 Common::SeekableReadStream *in;
290 char filename[30];
291
292 if (_tblList == NULL)
293 return 0;
294
295 p = _tblList + 32;
296
297 min_num = READ_BE_UINT16(p);
298 max_num = READ_BE_UINT16(p + 2);
299 file_num = *(p + 4);
300 p += 6;
301
302 while (min_num) {
303 if ((subrId >= min_num) && (subrId <= max_num)) {
304 _subroutineList = _subroutineListOrg;
305 _tablesHeapPtr = _tablesHeapPtrOrg;
306 _tablesHeapCurPos = _tablesHeapCurPosOrg;
307 _stringIdLocalMin = 1;
308 _stringIdLocalMax = 0;
309
310 sprintf(filename, "TABLES%.2d", file_num);
311 in = openTablesFile(filename);
312 readSubroutineBlock(in);
313 closeTablesFile(in);
314
315 alignTableMem();
316
317 _tablesheapPtrNew = _tablesHeapPtr;
318 _tablesHeapCurPosNew = _tablesHeapCurPos;
319
320 if (_tablesHeapCurPos > _tablesHeapSize)
321 error("loadTablesIntoMem: Out of table memory");
322 return 1;
323 }
324
325 min_num = READ_BE_UINT16(p);
326 max_num = READ_BE_UINT16(p + 2);
327 file_num = *(p + 4);
328 p += 6;
329 }
330
331 debug(1,"loadTablesIntoMem: didn't find %d", subrId);
332 return 0;
333 }
334
loadTablesIntoMem(uint16 subrId)335 bool AGOSEngine_Waxworks::loadTablesIntoMem(uint16 subrId) {
336 byte *p;
337 uint min_num, max_num;
338 Common::SeekableReadStream *in;
339
340 p = _tblList;
341 if (p == NULL)
342 return 0;
343
344 while (*p) {
345 Common::String filename;
346 while (*p)
347 filename += *p++;
348 p++;
349
350 if (getPlatform() == Common::kPlatformAcorn) {
351 filename += ".DAT";
352 }
353
354 for (;;) {
355 min_num = READ_BE_UINT16(p); p += 2;
356 if (min_num == 0)
357 break;
358
359 max_num = READ_BE_UINT16(p); p += 2;
360
361 if (subrId >= min_num && subrId <= max_num) {
362 _subroutineList = _subroutineListOrg;
363 _tablesHeapPtr = _tablesHeapPtrOrg;
364 _tablesHeapCurPos = _tablesHeapCurPosOrg;
365 _stringIdLocalMin = 1;
366 _stringIdLocalMax = 0;
367
368 in = openTablesFile(filename.c_str());
369 readSubroutineBlock(in);
370 closeTablesFile(in);
371 if (getGameType() == GType_SIMON2) {
372 _sound->loadSfxTable(getFileName(GAME_GMEFILE), _gameOffsetsPtr[atoi(filename.c_str() + 6) - 1 + _soundIndexBase]);
373 } else if (getGameType() == GType_SIMON1 && getPlatform() == Common::kPlatformWindows) {
374 filename.setChar('S', 0);
375 filename.setChar('F', 1);
376 filename.setChar('X', 2);
377 filename.setChar('X', 3);
378 filename.setChar('X', 4);
379 filename.setChar('X', 5);
380 if (atoi(filename.c_str() + 6) != 1 && atoi(filename.c_str() + 6) != 30)
381 _sound->readSfxFile(filename);
382 }
383
384 alignTableMem();
385
386 _tablesheapPtrNew = _tablesHeapPtr;
387 _tablesHeapCurPosNew = _tablesHeapCurPos;
388
389 if (_tablesHeapCurPos > _tablesHeapSize)
390 error("loadTablesIntoMem: Out of table memory");
391 return 1;
392 }
393 }
394 }
395
396 debug(1,"loadTablesIntoMem: didn't find %d", subrId);
397 return 0;
398 }
399
loadXTablesIntoMem(uint16 subrId)400 bool AGOSEngine::loadXTablesIntoMem(uint16 subrId) {
401 byte *p;
402 int i;
403 uint min_num, max_num;
404 char filename[30];
405 Common::SeekableReadStream *in;
406
407 p = _xtblList;
408 if (p == NULL)
409 return 0;
410
411 while (*p) {
412 for (i = 0; *p; p++, i++)
413 filename[i] = *p;
414 filename[i] = 0;
415 p++;
416
417 for (;;) {
418 min_num = READ_BE_UINT16(p);
419 p += 2;
420
421 if (min_num == 0)
422 break;
423
424 max_num = READ_BE_UINT16(p);
425 p += 2;
426
427 if (subrId >= min_num && subrId <= max_num) {
428 _subroutineList = _xsubroutineListOrg;
429 _tablesHeapPtr = _xtablesHeapPtrOrg;
430 _tablesHeapCurPos = _xtablesHeapCurPosOrg;
431 _stringIdLocalMin = 1;
432 _stringIdLocalMax = 0;
433
434 in = openTablesFile(filename);
435 readSubroutineBlock(in);
436 closeTablesFile(in);
437
438 alignTableMem();
439
440 _subroutineListOrg = _subroutineList;
441 _tablesHeapPtrOrg = _tablesHeapPtr;
442 _tablesHeapCurPosOrg = _tablesHeapCurPos;
443 _tablesheapPtrNew = _tablesHeapPtr;
444 _tablesHeapCurPosNew = _tablesHeapCurPos;
445
446 return 1;
447 }
448 }
449 }
450
451 debug(1,"loadXTablesIntoMem: didn't find %d", subrId);
452 return 0;
453 }
454
closeTablesFile(Common::SeekableReadStream * in)455 void AGOSEngine::closeTablesFile(Common::SeekableReadStream *in) {
456 if (getFeatures() & GF_OLD_BUNDLE) {
457 delete in;
458 }
459 }
460
createSubroutine(uint16 id)461 Subroutine *AGOSEngine::createSubroutine(uint16 id) {
462 Subroutine *sub;
463
464 alignTableMem();
465
466 sub = (Subroutine *)allocateTable(sizeof(Subroutine));
467 sub->id = id;
468 sub->first = 0;
469 sub->next = _subroutineList;
470 _subroutineList = sub;
471 return sub;
472 }
473
createSubroutineLine(Subroutine * sub,int where)474 SubroutineLine *AGOSEngine::createSubroutineLine(Subroutine *sub, int where) {
475 SubroutineLine *sl, *cur_sl = NULL, *last_sl = NULL;
476
477 if (sub->id == 0)
478 sl = (SubroutineLine *)allocateTable(SUBROUTINE_LINE_BIG_SIZE);
479 else
480 sl = (SubroutineLine *)allocateTable(SUBROUTINE_LINE_SMALL_SIZE);
481
482 // where is what offset to insert the line at, locate the proper beginning line
483 if (sub->first != 0) {
484 cur_sl = (SubroutineLine *)((byte *)sub + sub->first);
485 while (where) {
486 last_sl = cur_sl;
487 cur_sl = (SubroutineLine *)((byte *)sub + cur_sl->next);
488 if ((byte *)cur_sl == (byte *)sub)
489 break;
490 where--;
491 }
492 }
493
494 if (last_sl != NULL) {
495 // Insert the subroutine line in the middle of the link
496 last_sl->next = (byte *)sl - (byte *)sub;
497 sl->next = (byte *)cur_sl - (byte *)sub;
498 } else {
499 // Insert the subroutine line at the head of the link
500 sl->next = sub->first;
501 sub->first = (byte *)sl - (byte *)sub;
502 }
503
504 return sl;
505 }
506
runSubroutine101()507 void AGOSEngine::runSubroutine101() {
508 Subroutine *sub;
509
510 sub = getSubroutineByID(101);
511 if (sub != NULL)
512 startSubroutineEx(sub);
513
514 permitInput();
515 }
516
startSubroutine(Subroutine * sub)517 int AGOSEngine::startSubroutine(Subroutine *sub) {
518 int result = -1;
519 SubroutineLine *sl = (SubroutineLine *)((byte *)sub + sub->first);
520
521 const byte *old_code_ptr = _codePtr;
522 Subroutine *old_currentTable = _currentTable;
523 SubroutineLine *old_currentLine = _currentLine;
524 SubroutineLine *old_classLine = _classLine;
525 int16 old_classMask = _classMask;
526 int16 old_classMode1 = _classMode1;
527 int16 old_classMode2 = _classMode2;
528
529 _classLine = 0;
530 _classMask = 0;
531 _classMode1 = 0;
532 _classMode2 = 0;
533
534 if (DebugMan.isDebugChannelEnabled(kDebugSubroutine))
535 dumpSubroutine(sub);
536
537 if (++_recursionDepth > 40)
538 error("Recursion error");
539
540 // WORKAROUND: If the game is saved, right after Simon is thrown in the dungeon of Sordid's Fortress of Doom,
541 // the saved game fails to load correctly. When loading the saved game, the sequence of Simon waking is started,
542 // before the scene is actually reloaded, due to a script bug. We manually add the extra script code from the
543 // updated DOS CD release, which fixed this particular script bug.
544 if (getGameType() == GType_SIMON2 && sub->id == 12101) {
545 const byte bit = 228;
546 if ((_bitArrayTwo[bit / 16] & (1 << (bit & 15))) != 0 && (int)readVariable(34) == -1) {
547 _bitArrayTwo[228 / 16] &= ~(1 << (bit & 15));
548 writeVariable(34, 1);
549 }
550 }
551
552 _currentTable = sub;
553 restart:
554
555 if (shouldQuit())
556 return result;
557
558 while ((byte *)sl != (byte *)sub) {
559 _currentLine = sl;
560 if (checkIfToRunSubroutineLine(sl, sub)) {
561 _codePtr = (byte *)sl;
562 if (sub->id)
563 _codePtr += 2;
564 else
565 _codePtr += 8;
566
567 debugC(kDebugOpcode, "; %d", sub->id);
568 result = runScript();
569 if (result != 0) {
570 break;
571 }
572 }
573 sl = (SubroutineLine *)((byte *)sub + sl->next);
574 }
575
576 // WORKAROUND: Feeble walks in the incorrect direction, when looking at the Vent in the Research and Testing area of
577 // the Company Central Command Compound. We manually add the extra script code from the updated English 2CD release,
578 // which fixed this particular script bug.
579 if (getGameType() == GType_FF && _language == Common::EN_ANY) {
580 if (sub->id == 39125 && readVariable(84) == 2) {
581 writeVariable(1, 1136);
582 writeVariable(2, 346);
583 }
584 if (sub->id == 39126 && readVariable(84) == 2) {
585 Subroutine *tmpSub = getSubroutineByID(80);
586 if (tmpSub != NULL) {
587 startSubroutine(tmpSub);
588 }
589 }
590 }
591
592 if (_classMode1) {
593 _subjectItem = nextInByClass(_subjectItem, _classMask);
594 if (!_subjectItem) {
595 _classMode1 = 0;
596 } else {
597 delay(0);
598 sl = _classLine; /* Rescanner */
599 goto restart;
600 }
601 }
602 if (_classMode2) {
603 _objectItem = nextInByClass(_objectItem, _classMask);
604 if (!_objectItem) {
605 _classMode2 = 0;
606 } else {
607 delay(0);
608 sl = _classLine; /* Rescanner */
609 goto restart;
610 }
611 }
612
613 /* result -10 means restart subroutine */
614 if (result == -10) {
615 delay(0);
616 sl = (SubroutineLine *)((byte *)sub + sub->first);
617 goto restart;
618 }
619
620 _codePtr = old_code_ptr;
621 _currentLine = old_currentLine;
622 _currentTable = old_currentTable;
623 _classLine = old_classLine;
624 _classMask = old_classMask;
625 _classMode1 = old_classMode2;
626 _classMode2 = old_classMode1;
627 _findNextPtr = 0;
628
629 _recursionDepth--;
630 return result;
631 }
632
startSubroutineEx(Subroutine * sub)633 int AGOSEngine::startSubroutineEx(Subroutine *sub) {
634 return startSubroutine(sub);
635 }
636
checkIfToRunSubroutineLine(SubroutineLine * sl,Subroutine * sub)637 bool AGOSEngine::checkIfToRunSubroutineLine(SubroutineLine *sl, Subroutine *sub) {
638 if (sub->id)
639 return true;
640
641 if (sl->verb != -1 && sl->verb != _scriptVerb &&
642 (sl->verb != -2 || _scriptVerb != -1))
643 return false;
644
645 if (sl->noun1 != -1 && sl->noun1 != _scriptNoun1 &&
646 (sl->noun1 != -2 || _scriptNoun1 != -1))
647 return false;
648
649 if (sl->noun2 != -1 && sl->noun2 != _scriptNoun2 &&
650 (sl->noun2 != -2 || _scriptNoun2 != -1))
651 return false;
652
653 return true;
654 }
655
readSubroutineBlock(Common::SeekableReadStream * in)656 void AGOSEngine::readSubroutineBlock(Common::SeekableReadStream *in) {
657 while (in->readUint16BE() == 0) {
658 readSubroutine(in, createSubroutine(in->readUint16BE()));
659 }
660 }
readSubroutine(Common::SeekableReadStream * in,Subroutine * sub)661 void AGOSEngine::readSubroutine(Common::SeekableReadStream *in, Subroutine *sub) {
662 while (in->readUint16BE() == 0) {
663 readSubroutineLine(in, createSubroutineLine(sub, 0xFFFF), sub);
664 }
665 }
666
readSubroutineLine(Common::SeekableReadStream * in,SubroutineLine * sl,Subroutine * sub)667 void AGOSEngine::readSubroutineLine(Common::SeekableReadStream *in, SubroutineLine *sl, Subroutine *sub) {
668 byte line_buffer[2048], *q = line_buffer;
669 int size;
670
671 if (sub->id == 0) {
672 sl->verb = in->readUint16BE();
673 sl->noun1 = in->readUint16BE();
674 sl->noun2 = in->readUint16BE();
675 } else if (getGameType() == GType_ELVIRA1) {
676 in->readUint16BE();
677 in->readUint16BE();
678 in->readUint16BE();
679 }
680
681 if (getGameType() == GType_ELVIRA1) {
682 int16 tmp = in->readUint16BE();
683 WRITE_BE_UINT16(q, tmp);
684 while (tmp != 10000) {
685 if (READ_BE_UINT16(q) == 198) {
686 in->readUint16BE();
687 } else {
688 q = readSingleOpcode(in, q);
689 }
690
691 tmp = in->readUint16BE();
692 WRITE_BE_UINT16(q, tmp);
693 }
694 } else {
695 while ((*q = in->readByte()) != 0xFF) {
696 if (*q == 87) {
697 in->readUint16BE();
698 } else {
699 q = readSingleOpcode(in, q);
700 }
701 }
702 }
703
704 size = (q - line_buffer + 2);
705 memcpy(allocateTable(size), line_buffer, size);
706 }
707
readSingleOpcode(Common::SeekableReadStream * in,byte * ptr)708 byte *AGOSEngine::readSingleOpcode(Common::SeekableReadStream *in, byte *ptr) {
709 int i, l;
710 const char *stringPtr;
711 uint16 opcode, val;
712
713 const char *const *table;
714
715 if (getGameType() == GType_PP)
716 table = opcodeArgTable_puzzlepack;
717 else if (getGameType() == GType_FF)
718 table = opcodeArgTable_feeblefiles;
719 else if (getGameType() == GType_SIMON2 && (getFeatures() & GF_TALKIE))
720 table = opcodeArgTable_simon2talkie;
721 else if (getGameType() == GType_SIMON2)
722 table = opcodeArgTable_simon2dos;
723 else if (getGameType() == GType_SIMON1 && (getFeatures() & GF_TALKIE))
724 table = opcodeArgTable_simon1talkie;
725 else if (getGameType() == GType_SIMON1)
726 table = opcodeArgTable_simon1dos;
727 else if (getGameType() == GType_WW)
728 table = opcodeArgTable_waxworks;
729 else if (getGameType() == GType_ELVIRA2)
730 table = opcodeArgTable_elvira2;
731 else
732 table = opcodeArgTable_elvira1;
733
734 i = 0;
735 if (getGameType() == GType_ELVIRA1) {
736 opcode = READ_BE_UINT16(ptr);
737 ptr += 2;
738 } else {
739 opcode = *ptr++;
740 }
741
742 stringPtr = table[opcode];
743 if (!stringPtr)
744 error("Unable to locate opcode table. Perhaps you are using the wrong game target?");
745
746 for (;;) {
747 if (stringPtr[i] == ' ')
748 return ptr;
749
750 l = stringPtr[i++];
751
752 switch (l) {
753 case 'F':
754 case 'N':
755 case 'S':
756 case 'a':
757 case 'n':
758 case 'p':
759 case 'v':
760 case '3':
761 val = in->readUint16BE();
762 WRITE_BE_UINT16(ptr, val); ptr += 2;
763 break;
764
765 case 'B':
766 if (getGameType() == GType_ELVIRA1) {
767 val = in->readUint16BE();
768 WRITE_BE_UINT16(ptr, val); ptr += 2;
769 } else {
770 *ptr++ = in->readByte();
771 if (ptr[-1] == 0xFF) {
772 *ptr++ = in->readByte();
773 }
774 }
775 break;
776
777 case 'I':
778 val = in->readUint16BE();
779 switch (val) {
780 case 1:
781 val = 0xFFFF;
782 break;
783 case 3:
784 val = 0xFFFD;
785 break;
786 case 5:
787 val = 0xFFFB;
788 break;
789 case 7:
790 val = 0xFFF9;
791 break;
792 case 9:
793 val = 0xFFF7;
794 break;
795 default:
796 val = fileReadItemID(in);
797 break;
798 }
799 WRITE_BE_UINT16(ptr, val); ptr += 2;
800 break;
801
802 case 'T':
803 val = in->readUint16BE();
804 switch (val) {
805 case 0:
806 val = 0xFFFF;
807 break;
808 case 3:
809 val = 0xFFFD;
810 break;
811 default:
812 val = (uint16)in->readUint32BE();
813 break;
814 }
815 WRITE_BE_UINT16(ptr, val); ptr += 2;
816 break;
817 default:
818 error("readSingleOpcode: Bad cmd table entry %c", l);
819 }
820 }
821 }
822
823 } // End of namespace AGOS
824