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/file.h"
24 #include "common/textconsole.h"
25
26 #include "agos/intern.h"
27 #include "agos/agos.h"
28 #include "agos/vga.h"
29
30 namespace AGOS {
31
allocateChildBlock(Item * i,uint type,uint size)32 Child *AGOSEngine::allocateChildBlock(Item *i, uint type, uint size) {
33 Child *child = (Child *)allocateItem(size);
34 child->next = i->children;
35 i->children = child;
36 child->type = type;
37 return child;
38 }
39
allocateItem(uint size)40 void *AGOSEngine::allocateItem(uint size) {
41 byte *item = new byte[size];
42
43 memset(item, 0, size);
44 _itemHeap.push_back(item);
45 return item;
46 }
47
allocItemHeap()48 void AGOSEngine::allocItemHeap() {
49 _itemHeap.clear();
50 }
51
hasIcon(Item * item)52 bool AGOSEngine_Elvira2::hasIcon(Item *item) {
53 SubObject *child = (SubObject *)findChildOfType(item, kObjectType);
54 return (child && (child->objectFlags & kOFIcon) != 0);
55 }
56
hasIcon(Item * item)57 bool AGOSEngine::hasIcon(Item *item) {
58 return (getUserFlag(item, 7) != 0);
59 }
60
itemGetIconNumber(Item * item)61 uint AGOSEngine_Elvira2::itemGetIconNumber(Item *item) {
62 SubObject *child = (SubObject *)findChildOfType(item, kObjectType);
63 uint offs;
64
65 if (child == NULL || !(child->objectFlags & kOFIcon))
66 return 0;
67
68 offs = getOffsetOfChild2Param(child, 0x10);
69 return child->objectFlagValue[offs];
70 }
71
itemGetIconNumber(Item * item)72 uint AGOSEngine::itemGetIconNumber(Item *item) {
73 return getUserFlag(item, 7);
74 }
75
setItemState(Item * item,int value)76 void AGOSEngine::setItemState(Item *item, int value) {
77 item->state = value;
78 }
79
createPlayer()80 void AGOSEngine::createPlayer() {
81 SubPlayer *p;
82
83 _currentPlayer = _itemArrayPtr[1];
84 _currentPlayer->adjective = -1;
85 _currentPlayer->noun = 10000;
86
87 p = (SubPlayer *)allocateChildBlock(_currentPlayer, kPlayerType, sizeof(SubPlayer));
88 if (p == NULL)
89 error("createPlayer: player create failure");
90
91 p->size = 0;
92 p->weight = 0;
93 p->strength = 6000;
94 p->flags = 1; // Male
95 p->level = 1;
96 p->score = 0;
97
98 setUserFlag(_currentPlayer, 0, 0);
99 }
100
findChildOfType(Item * i,uint type)101 Child *AGOSEngine::findChildOfType(Item *i, uint type) {
102 Item *b = NULL;
103 Child *child = i->children;
104
105 for (; child; child = child->next) {
106 if (child->type == type)
107 return child;
108 if (child->type == 255)
109 b = derefItem(((SubInherit *)(child))->inMaster);
110 }
111 if (b) {
112 child = b->children;
113 for (; child; child = child->next) {
114 if (child->type == type)
115 return child;
116 }
117 }
118
119 return NULL;
120 }
121
getUserFlag(Item * item,int a)122 int AGOSEngine::getUserFlag(Item *item, int a) {
123 SubUserFlag *subUserFlag;
124
125 subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType);
126 if (subUserFlag == NULL)
127 return 0;
128
129 int max = (getGameType() == GType_ELVIRA1) ? 7 : 3;
130 if (a < 0 || a > max)
131 return 0;
132
133 return subUserFlag->userFlags[a];
134 }
135
getUserFlag1(Item * item,int a)136 int AGOSEngine::getUserFlag1(Item *item, int a) {
137 SubUserFlag *subUserFlag;
138
139 if (item == NULL || item == _dummyItem2 || item == _dummyItem3)
140 return -1;
141
142 subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType);
143 if (subUserFlag == NULL)
144 return 0;
145
146 if (a < 0 || a > 7)
147 return 0;
148
149 return subUserFlag->userFlags[a];
150 }
151
setUserFlag(Item * item,int a,int b)152 void AGOSEngine::setUserFlag(Item *item, int a, int b) {
153 SubUserFlag *subUserFlag;
154
155 subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType);
156 if (subUserFlag == NULL) {
157 subUserFlag = (SubUserFlag *)allocateChildBlock(item, kUserFlagType, sizeof(SubUserFlag));
158 }
159
160 if (a < 0 || a > 7)
161 return;
162
163 subUserFlag->userFlags[a] = b;
164 }
165
getUserItem(Item * item,int n)166 int AGOSEngine::getUserItem(Item *item, int n) {
167 SubUserFlag *subUserFlag;
168
169 subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType);
170 if (subUserFlag == NULL)
171 return 0;
172
173 if (n < 0 || n > 0)
174 return 0;
175
176 return subUserFlag->userItems[n];
177 }
178
setUserItem(Item * item,int n,int m)179 void AGOSEngine::setUserItem(Item *item, int n, int m) {
180 SubUserFlag *subUserFlag;
181
182 subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType);
183 if (subUserFlag == NULL) {
184 subUserFlag = (SubUserFlag *)allocateChildBlock(item, kUserFlagType, sizeof(SubUserFlag));
185 }
186
187 if (n == 0)
188 subUserFlag->userItems[n] = m;
189 }
190
isRoom(Item * item)191 bool AGOSEngine::isRoom(Item *item) {
192 return findChildOfType(item, kRoomType) != NULL;
193 }
194
isObject(Item * item)195 bool AGOSEngine::isObject(Item *item) {
196 return findChildOfType(item, kObjectType) != NULL;
197 }
198
isPlayer(Item * item)199 bool AGOSEngine::isPlayer(Item *item) {
200 return findChildOfType(item, kPlayerType) != NULL;
201 }
202
getOffsetOfChild2Param(SubObject * child,uint prop)203 uint AGOSEngine::getOffsetOfChild2Param(SubObject *child, uint prop) {
204 uint m = 1;
205 uint offset = 0;
206 while (m != prop) {
207 if (child->objectFlags & m)
208 offset++;
209 m *= 2;
210 }
211 return offset;
212 }
213
me()214 Item *AGOSEngine::me() {
215 if (_currentPlayer)
216 return _currentPlayer;
217 return _dummyItem1;
218 }
219
actor()220 Item *AGOSEngine::actor() {
221 error("actor: is this code ever used?");
222 //if (_actorPlayer)
223 // return _actorPlayer;
224 return _dummyItem1; // for compilers that don't support NORETURN
225 }
226
getNextItemPtr()227 Item *AGOSEngine::getNextItemPtr() {
228 int a = getNextWord();
229 switch (a) {
230 case -1:
231 return _subjectItem;
232 case -3:
233 return _objectItem;
234 case -5:
235 return me();
236 case -7:
237 return actor();
238 case -9:
239 return derefItem(me()->parent);
240 default:
241 return derefItem(a);
242 }
243 }
244
getNextItemPtrStrange()245 Item *AGOSEngine::getNextItemPtrStrange() {
246 int a = getNextWord();
247 switch (a) {
248 case -1:
249 return _subjectItem;
250 case -3:
251 return _objectItem;
252 case -5:
253 return _dummyItem2;
254 case -7:
255 return NULL;
256 case -9:
257 return _dummyItem3;
258 default:
259 return derefItem(a);
260 }
261 }
262
getNextItemID()263 uint AGOSEngine::getNextItemID() {
264 int a = getNextWord();
265 switch (a) {
266 case -1:
267 return itemPtrToID(_subjectItem);
268 case -3:
269 return itemPtrToID(_objectItem);
270 case -5:
271 return getItem1ID();
272 case -7:
273 return 0;
274 case -9:
275 return me()->parent;
276 default:
277 return a;
278 }
279 }
280
setItemParent(Item * item,Item * parent)281 void AGOSEngine::setItemParent(Item *item, Item *parent) {
282 Item *old_parent = derefItem(item->parent);
283
284 if (item == parent)
285 error("setItemParent: Trying to set item as its own parent");
286
287 // unlink it if it has a parent
288 if (old_parent)
289 unlinkItem(item);
290 itemChildrenChanged(old_parent);
291 linkItem(item, parent);
292 itemChildrenChanged(parent);
293 }
294
itemChildrenChanged(Item * item)295 void AGOSEngine::itemChildrenChanged(Item *item) {
296 int i;
297 WindowBlock *window;
298
299 if (_noParentNotify)
300 return;
301
302 mouseOff();
303
304 for (i = 0; i != 8; i++) {
305 window = _windowArray[i];
306 if (window && window->iconPtr && window->iconPtr->itemRef == item) {
307 if (_fcsData1[i]) {
308 _fcsData2[i] = true;
309 } else {
310 _fcsData2[i] = false;
311 drawIconArray(i, item, window->iconPtr->line, window->iconPtr->classMask);
312 }
313 }
314 }
315
316 mouseOn();
317 }
318
unlinkItem(Item * item)319 void AGOSEngine::unlinkItem(Item *item) {
320 Item *first, *parent, *next;
321
322 // can't unlink item without parent
323 if (item->parent == 0)
324 return;
325
326 // get parent and first child of parent
327 parent = derefItem(item->parent);
328 first = derefItem(parent->child);
329
330 // the node to remove is first in the parent's children?
331 if (first == item) {
332 parent->child = item->next;
333 item->parent = 0;
334 item->next = 0;
335 return;
336 }
337
338 for (;;) {
339 if (!first)
340 error("unlinkItem: parent empty");
341 if (first->next == 0)
342 error("unlinkItem: parent does not contain child");
343
344 next = derefItem(first->next);
345 if (next == item) {
346 first->next = next->next;
347 item->parent = 0;
348 item->next = 0;
349 return;
350 }
351 first = next;
352 }
353 }
354
linkItem(Item * item,Item * parent)355 void AGOSEngine::linkItem(Item *item, Item *parent) {
356 uint id;
357 // Don't allow that an item that is already linked is relinked
358 if (item->parent)
359 return;
360
361 id = itemPtrToID(parent);
362 item->parent = id;
363
364 if (parent != 0) {
365 item->next = parent->child;
366 parent->child = itemPtrToID(item);
367 } else {
368 item->next = 0;
369 }
370 }
371
wordMatch(Item * item,int16 a,int16 n)372 int AGOSEngine::wordMatch(Item *item, int16 a, int16 n) {
373 if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
374 if (a == -1 && n == -1)
375 return 1;
376 }
377 if (a == -1 && n == item->noun)
378 return 1;
379 if (a == item->adjective && n == item->noun)
380 return 1;
381
382 return 0;
383 }
384
derefItem(uint item)385 Item *AGOSEngine::derefItem(uint item) {
386 if (item >= _itemArraySize)
387 error("derefItem: invalid item %d", item);
388 return _itemArrayPtr[item];
389 }
390
findInByClass(Item * i,int16 m)391 Item *AGOSEngine::findInByClass(Item *i, int16 m) {
392 i = derefItem(i->child);
393 while (i) {
394 if (i->classFlags & m) {
395 _findNextPtr = derefItem(i->next);
396 return i;
397 }
398 if (m == 0) {
399 _findNextPtr = derefItem(i->next);
400 return i;
401 }
402 i = derefItem(i->next);
403 }
404 return NULL;
405 }
406
nextInByClass(Item * i,int16 m)407 Item *AGOSEngine::nextInByClass(Item *i, int16 m) {
408 i = _findNextPtr;
409 while (i) {
410 if (i->classFlags & m) {
411 _findNextPtr = derefItem(i->next);
412 return i;
413 }
414 if (m == 0) {
415 _findNextPtr = derefItem(i->next);
416 return i;
417 }
418 i = derefItem(i->next);
419 }
420 return NULL;
421 }
422
findMaster(int16 a,int16 n)423 Item *AGOSEngine::findMaster(int16 a, int16 n) {
424 uint j;
425
426 for (j = 1; j < _itemArraySize; j++) {
427 Item *item = derefItem(j);
428 if (item == NULL)
429 continue;
430
431 if (wordMatch(item, a, n))
432 return item;
433 }
434
435 return NULL;
436 }
437
nextMaster(Item * i,int16 a,int16 n)438 Item *AGOSEngine::nextMaster(Item *i, int16 a, int16 n) {
439 uint j;
440 uint first = itemPtrToID(i) + 1;
441
442 for (j = first; j < _itemArraySize; j++) {
443 Item *item = derefItem(j);
444 if (item == NULL)
445 continue;
446
447 if (wordMatch(item, a, n))
448 return item;
449 }
450
451 return NULL;
452 }
453
itemPtrToID(Item * id)454 uint AGOSEngine::itemPtrToID(Item *id) {
455 uint i;
456 for (i = 0; i != _itemArraySize; i++)
457 if (_itemArrayPtr[i] == id)
458 return i;
459 error("itemPtrToID: not found");
460 return 0; // for compilers that don't support NORETURN
461 }
462
463 } // End of namespace AGOS
464