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
24
25 #include "common/file.h"
26 #include "common/textconsole.h"
27
28 #include "agos/agos.h"
29 #include "agos/intern.h"
30
31 namespace AGOS {
32
getBackExit(int n)33 uint16 AGOSEngine::getBackExit(int n) {
34 switch (n) {
35 case 0:
36 return 2;
37 case 1:
38 return 3;
39 case 2:
40 return 0;
41 case 3:
42 return 1;
43 case 4:
44 return 5;
45 case 5:
46 return 4;
47 }
48
49 return 0;
50 }
51
getDoorState(Item * item,uint16 d)52 uint16 AGOSEngine::getDoorState(Item *item, uint16 d) {
53 uint16 mask = 3;
54 uint16 n;
55
56 SubRoom *subRoom = (SubRoom *)findChildOfType(item, kRoomType);
57 if (subRoom == NULL)
58 return 0;
59
60 d <<= 1;
61 mask <<= d;
62 n = subRoom->roomExitStates & mask;
63 n >>= d;
64
65 return n;
66 }
67
getExitOf(Item * item,uint16 d)68 uint16 AGOSEngine::getExitOf(Item *item, uint16 d) {
69 SubRoom *subRoom;
70 uint16 x;
71 uint16 y = 0;
72
73 subRoom = (SubRoom *)findChildOfType(item, kRoomType);
74 if (subRoom == NULL)
75 return 0;
76 x = d;
77 while (x > y) {
78 if (getDoorState(item, y) == 0)
79 d--;
80 y++;
81 }
82 return subRoom->roomExit[d];
83 }
84
changeDoorState(SubRoom * r,uint16 d,uint16 n)85 void AGOSEngine::changeDoorState(SubRoom *r, uint16 d, uint16 n) {
86 uint16 mask=3;
87 d <<= 1;
88 mask <<= d;
89 n <<= d;
90 r->roomExitStates &= ~mask;
91 r->roomExitStates |= n;
92 }
93
setDoorState(Item * i,uint16 d,uint16 n)94 void AGOSEngine::setDoorState(Item *i, uint16 d, uint16 n) {
95 Item *j;
96 SubRoom *r, *r1;
97 uint16 d1;
98 uint16 y = 0;
99
100 r = (SubRoom *)findChildOfType(i, kRoomType);
101 if (r == NULL)
102 return;
103 d1 = d;
104 while (d > y) {
105 if (getDoorState(i, y) == 0)
106 d1--;
107 y++;
108 }
109 changeDoorState(r, d, n);
110
111 j = derefItem(r->roomExit[d1]);
112 if (j == NULL)
113 return;
114 r1 = (SubRoom *)findChildOfType(j, kRoomType);
115 if (r1 == NULL)
116 return;
117 d = getBackExit(d);
118 d1 = d;
119 y = 0;
120 while (d > y) {
121 if (getDoorState(j, y) == 0)
122 d1--;
123 y++;
124 }
125 /* Check are a complete exit pair */
126 if (derefItem(r1->roomExit[d1]) != i)
127 return;
128 /* Change state of exit coming back */
129 changeDoorState(r1, d, n);
130 }
131
132 // Elvira 1 specific
getDoorOf(Item * i,uint16 d)133 Item *AGOSEngine::getDoorOf(Item *i, uint16 d) {
134 SubGenExit *g;
135 Item *x;
136
137 g = (SubGenExit *)findChildOfType(i, kGenExitType);
138 if (g == NULL)
139 return 0;
140
141 x = derefItem(g->dest[d]);
142 if (x == NULL)
143 return 0;
144 if (isRoom(x))
145 return 0;
146 return x;
147 }
148
getExitOf_e1(Item * item,uint16 d)149 Item *AGOSEngine::getExitOf_e1(Item *item, uint16 d) {
150 SubGenExit *g;
151 Item *x;
152
153 g = (SubGenExit *)findChildOfType(item, kGenExitType);
154 if (g == NULL)
155 return 0;
156
157 x = derefItem(g->dest[d]);
158 if (x == NULL)
159 return 0;
160 if (isRoom(x))
161 return x;
162 if (x->state != 0)
163 return 0;
164 return derefItem(x->parent);
165 }
166
moveDirn(Item * i,uint x)167 void AGOSEngine_Waxworks::moveDirn(Item *i, uint x) {
168 Item *d;
169 uint16 n;
170
171 if (i->parent == 0)
172 return;
173
174 n = getExitOf(derefItem(i->parent), x);
175 if (derefItem(n) == NULL) {
176 loadRoomItems(n);
177 n = getExitOf(derefItem(i->parent), x);
178 }
179
180 d = derefItem(n);
181 if (d) {
182 n = getDoorState(derefItem(i->parent), x);
183 if (n == 1) {
184 if (!canPlace(i, d))
185 setItemParent(i, d);
186 }
187 }
188 }
189
moveDirn(Item * i,uint x)190 void AGOSEngine_Elvira2::moveDirn(Item *i, uint x) {
191 SubSuperRoom *sr;
192 Item *d, *p;
193 uint16 a, n;
194
195 if (i->parent == 0)
196 return;
197
198 p = derefItem(i->parent);
199 if (findChildOfType(p, kSuperRoomType)) {
200 n = getExitState(p, _superRoomNumber,x);
201 if (n == 1) {
202 sr = (SubSuperRoom *)findChildOfType(p, kSuperRoomType);
203 switch (x) {
204 case 0: a = -(sr->roomX); break;
205 case 1: a = 1; break;
206 case 2: a = sr->roomX; break;
207 case 3: a = 0xFFFF; break;
208 case 4: a = -(sr->roomX * sr->roomY); break;
209 case 5: a = (sr->roomX * sr->roomY); break;
210 default: return;
211 }
212 _superRoomNumber += a;
213 }
214 return;
215 }
216
217 n = getExitOf(derefItem(i->parent), x);
218
219 d = derefItem(n);
220 if (d) {
221 n = getDoorState(derefItem(i->parent), x);
222 if (n == 1) {
223 if (!canPlace(i, d))
224 setItemParent(i, d);
225 }
226 }
227 }
228
moveDirn(Item * i,uint x)229 void AGOSEngine::moveDirn(Item *i, uint x) {
230 Item *d, *p;
231
232 p = derefItem(i->parent);
233 if (p == 0)
234 return;
235
236
237 d = getExitOf_e1(p, x);
238 if (d) {
239 if (canPlace(i, d))
240 return;
241
242 setItemParent(i, d);
243 return;
244 }
245
246 d = getDoorOf(p, x);
247 if (d) {
248 const byte *name = getStringPtrByID(d->itemName, true);
249 if (d->state == 1)
250 showMessageFormat("%s is closed.\n", name);
251 else
252 showMessageFormat("%s is locked.\n", name);
253 return;
254 }
255
256 showMessageFormat("You can't go that way.\n");
257 }
258
259 // Elvira 2 specific
changeExitStates(SubSuperRoom * sr,int n,int d,uint16 s)260 int AGOSEngine_Elvira2::changeExitStates(SubSuperRoom *sr, int n, int d, uint16 s) {
261 int b, bd;
262 uint16 mask;
263
264 switch (d) {
265 case 0:
266 b = -(sr->roomX);
267 bd = 2;
268 if (((n % (sr->roomX * sr->roomY)) / sr->roomX) == 0)
269 return 0;
270 else
271 break;
272 case 1:
273 b = 1;
274 bd = 3;
275 if (((n % (sr->roomX * sr->roomY)) % sr->roomX) == 0)
276 return 0;
277 else
278 break;
279 case 2:
280 b = sr->roomX;
281 bd = 0;
282 if (((n % (sr->roomX * sr->roomY)) / sr->roomX) == (sr->roomY - 1))
283 return 0;
284 else
285 break;
286 case 3:
287 b = -1;
288 bd = 1;
289 if (((n % (sr->roomX * sr->roomY)) % sr->roomX) == 1)
290 return 0;
291 else
292 break;
293 case 4:
294 b = -(sr->roomX * sr->roomY);
295 bd = 5;
296 if (n < (sr->roomX * sr->roomY))
297 return 0;
298 else
299 break;
300 case 5:
301 b = sr->roomX * sr->roomY;
302 bd = 4;
303 if (n > (sr->roomX * sr->roomY * (sr->roomZ - 1)))
304 return 0;
305 else
306 break;
307 default:
308 return 0;
309 }
310
311 n--;
312 d <<= 1;
313 mask = (3 << d);
314 sr->roomExitStates[n] &= ~mask;
315 sr->roomExitStates[n] |= (s << d);
316
317 bd <<= 1;
318 mask = (3 << bd);
319 sr->roomExitStates[n + b] &= ~mask;
320 sr->roomExitStates[n + b] |= (s << bd);
321 return 1;
322 }
323
getExitState(Item * i,uint16 x,uint16 d)324 uint16 AGOSEngine_Elvira2::getExitState(Item *i, uint16 x, uint16 d) {
325 SubSuperRoom *sr;
326 uint16 mask = 3;
327 uint16 n;
328
329 sr = (SubSuperRoom *)findChildOfType(i, kSuperRoomType);
330 if (sr == NULL)
331 return 0;
332
333 d <<= 1;
334 mask <<= d;
335 n = sr->roomExitStates[x - 1] & mask;
336 n >>= d;
337 return n;
338 }
339
setExitState(Item * i,uint16 n,uint16 d,uint16 s)340 void AGOSEngine_Elvira2::setExitState(Item *i, uint16 n, uint16 d, uint16 s) {
341 SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(i, kSuperRoomType);
342 if (sr)
343 changeExitStates(sr, n, d, s);
344 }
345
setSRExit(Item * i,int n,int d,uint16 s)346 void AGOSEngine_Elvira2::setSRExit(Item *i, int n, int d, uint16 s) {
347 uint16 mask = 3;
348
349 SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(i, kSuperRoomType);
350 if (sr) {
351 n--;
352 d <<= 1;
353 mask <<= d;
354 s <<= d;
355 sr->roomExitStates[n] &= ~mask;
356 sr->roomExitStates[n] |= s;
357 }
358 }
359
360 // Waxworks specific
loadRoomItems(uint16 room)361 bool AGOSEngine::loadRoomItems(uint16 room) {
362 byte *p;
363 uint i, minNum, maxNum;
364 char filename[30];
365 Common::File in;
366 Item *item, *itemTmp;
367
368 if (_roomsList == NULL)
369 return 0;
370
371 _currentRoom = room;
372 room -= 2;
373
374 if (_roomsListPtr) {
375 p = _roomsListPtr;
376 for (;;) {
377 minNum = READ_BE_UINT16(p); p += 2;
378 if (minNum == 0)
379 break;
380
381 maxNum = READ_BE_UINT16(p); p += 2;
382
383 for (uint16 z = minNum; z <= maxNum; z++) {
384 uint16 itemNum = z + 2;
385 item = derefItem(itemNum);
386 _itemArrayPtr[itemNum] = 0;
387
388 uint16 num = (itemNum - _itemArrayInited);
389 _roomStates[num].state = item->state;
390 _roomStates[num].classFlags = item->classFlags;
391 SubRoom *subRoom = (SubRoom *)findChildOfType(item, kRoomType);
392 _roomStates[num].roomExitStates = subRoom->roomExitStates;
393 }
394 }
395 }
396
397 p = _roomsList;
398 while (*p) {
399 for (i = 0; *p; p++, i++)
400 filename[i] = *p;
401 filename[i] = 0;
402 p++;
403
404 _roomsListPtr = p;
405
406 for (;;) {
407 minNum = READ_BE_UINT16(p); p += 2;
408 if (minNum == 0)
409 break;
410
411 maxNum = READ_BE_UINT16(p); p += 2;
412
413 if (room >= minNum && room <= maxNum) {
414 in.open(filename);
415 if (in.isOpen() == false) {
416 error("loadRoomItems: Can't load rooms file '%s'", filename);
417 }
418
419 while ((i = in.readUint16BE()) != 0) {
420 uint16 itemNum = i + 2;
421
422 _itemArrayPtr[itemNum] = (Item *)allocateItem(sizeof(Item));
423 readItemFromGamePc(&in, _itemArrayPtr[itemNum]);
424
425 item = derefItem(itemNum);
426 item->parent = 0;
427 item->child = 0;
428
429 for (uint16 z = _itemArrayInited; z; z--) {
430 itemTmp = derefItem(z);
431
432 if (!itemTmp)
433 continue;
434 if (itemTmp->parent != itemNum)
435 continue;
436 if (item->child == 0) {
437 item->child = z;
438 continue;
439 }
440 uint16 child = item->child;
441 while (itemTmp->next != 0) {
442 if (itemTmp->next == child) {
443 item->child = z;
444 break;
445 }
446
447 itemTmp = derefItem(itemTmp->next);
448 }
449 }
450
451 uint16 num = (itemNum - _itemArrayInited);
452 item->state = _roomStates[num].state;
453 item->classFlags = _roomStates[num].classFlags;
454 SubRoom *subRoom = (SubRoom *)findChildOfType(item, kRoomType);
455 subRoom->roomExitStates = _roomStates[num].roomExitStates;
456
457 }
458 in.close();
459
460 return 1;
461 }
462 }
463 }
464
465 debug(1,"loadRoomItems: didn't find %d", room);
466 return 0;
467 }
468
469 } // End of namespace AGOS
470