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