/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "common/file.h" #include "common/textconsole.h" #include "agos/intern.h" #include "agos/agos.h" #include "agos/vga.h" namespace AGOS { Child *AGOSEngine::allocateChildBlock(Item *i, uint type, uint size) { Child *child = (Child *)allocateItem(size); child->next = i->children; i->children = child; child->type = type; return child; } void *AGOSEngine::allocateItem(uint size) { byte *item = new byte[size]; memset(item, 0, size); _itemHeap.push_back(item); return item; } void AGOSEngine::allocItemHeap() { _itemHeap.clear(); } bool AGOSEngine_Elvira2::hasIcon(Item *item) { SubObject *child = (SubObject *)findChildOfType(item, kObjectType); return (child && (child->objectFlags & kOFIcon) != 0); } bool AGOSEngine::hasIcon(Item *item) { return (getUserFlag(item, 7) != 0); } uint AGOSEngine_Elvira2::itemGetIconNumber(Item *item) { SubObject *child = (SubObject *)findChildOfType(item, kObjectType); uint offs; if (child == NULL || !(child->objectFlags & kOFIcon)) return 0; offs = getOffsetOfChild2Param(child, 0x10); return child->objectFlagValue[offs]; } uint AGOSEngine::itemGetIconNumber(Item *item) { return getUserFlag(item, 7); } void AGOSEngine::setItemState(Item *item, int value) { item->state = value; } void AGOSEngine::createPlayer() { SubPlayer *p; _currentPlayer = _itemArrayPtr[1]; _currentPlayer->adjective = -1; _currentPlayer->noun = 10000; p = (SubPlayer *)allocateChildBlock(_currentPlayer, kPlayerType, sizeof(SubPlayer)); if (p == NULL) error("createPlayer: player create failure"); p->size = 0; p->weight = 0; p->strength = 6000; p->flags = 1; // Male p->level = 1; p->score = 0; setUserFlag(_currentPlayer, 0, 0); } Child *AGOSEngine::findChildOfType(Item *i, uint type) { Item *b = NULL; Child *child = i->children; for (; child; child = child->next) { if (child->type == type) return child; if (child->type == 255) b = derefItem(((SubInherit *)(child))->inMaster); } if (b) { child = b->children; for (; child; child = child->next) { if (child->type == type) return child; } } return NULL; } int AGOSEngine::getUserFlag(Item *item, int a) { SubUserFlag *subUserFlag; subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (subUserFlag == NULL) return 0; int max = (getGameType() == GType_ELVIRA1) ? 7 : 3; if (a < 0 || a > max) return 0; return subUserFlag->userFlags[a]; } int AGOSEngine::getUserFlag1(Item *item, int a) { SubUserFlag *subUserFlag; if (item == NULL || item == _dummyItem2 || item == _dummyItem3) return -1; subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (subUserFlag == NULL) return 0; if (a < 0 || a > 7) return 0; return subUserFlag->userFlags[a]; } void AGOSEngine::setUserFlag(Item *item, int a, int b) { SubUserFlag *subUserFlag; subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (subUserFlag == NULL) { subUserFlag = (SubUserFlag *)allocateChildBlock(item, kUserFlagType, sizeof(SubUserFlag)); } if (a < 0 || a > 7) return; subUserFlag->userFlags[a] = b; } int AGOSEngine::getUserItem(Item *item, int n) { SubUserFlag *subUserFlag; subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (subUserFlag == NULL) return 0; if (n < 0 || n > 0) return 0; return subUserFlag->userItems[n]; } void AGOSEngine::setUserItem(Item *item, int n, int m) { SubUserFlag *subUserFlag; subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (subUserFlag == NULL) { subUserFlag = (SubUserFlag *)allocateChildBlock(item, kUserFlagType, sizeof(SubUserFlag)); } if (n == 0) subUserFlag->userItems[n] = m; } bool AGOSEngine::isRoom(Item *item) { return findChildOfType(item, kRoomType) != NULL; } bool AGOSEngine::isObject(Item *item) { return findChildOfType(item, kObjectType) != NULL; } bool AGOSEngine::isPlayer(Item *item) { return findChildOfType(item, kPlayerType) != NULL; } uint AGOSEngine::getOffsetOfChild2Param(SubObject *child, uint prop) { uint m = 1; uint offset = 0; while (m != prop) { if (child->objectFlags & m) offset++; m *= 2; } return offset; } Item *AGOSEngine::me() { if (_currentPlayer) return _currentPlayer; return _dummyItem1; } Item *AGOSEngine::actor() { error("actor: is this code ever used?"); //if (_actorPlayer) // return _actorPlayer; return _dummyItem1; // for compilers that don't support NORETURN } Item *AGOSEngine::getNextItemPtr() { int a = getNextWord(); switch (a) { case -1: return _subjectItem; case -3: return _objectItem; case -5: return me(); case -7: return actor(); case -9: return derefItem(me()->parent); default: return derefItem(a); } } Item *AGOSEngine::getNextItemPtrStrange() { int a = getNextWord(); switch (a) { case -1: return _subjectItem; case -3: return _objectItem; case -5: return _dummyItem2; case -7: return NULL; case -9: return _dummyItem3; default: return derefItem(a); } } uint AGOSEngine::getNextItemID() { int a = getNextWord(); switch (a) { case -1: return itemPtrToID(_subjectItem); case -3: return itemPtrToID(_objectItem); case -5: return getItem1ID(); case -7: return 0; case -9: return me()->parent; default: return a; } } void AGOSEngine::setItemParent(Item *item, Item *parent) { Item *old_parent = derefItem(item->parent); if (item == parent) error("setItemParent: Trying to set item as its own parent"); // unlink it if it has a parent if (old_parent) unlinkItem(item); itemChildrenChanged(old_parent); linkItem(item, parent); itemChildrenChanged(parent); } void AGOSEngine::itemChildrenChanged(Item *item) { int i; WindowBlock *window; if (_noParentNotify) return; mouseOff(); for (i = 0; i != 8; i++) { window = _windowArray[i]; if (window && window->iconPtr && window->iconPtr->itemRef == item) { if (_fcsData1[i]) { _fcsData2[i] = true; } else { _fcsData2[i] = false; drawIconArray(i, item, window->iconPtr->line, window->iconPtr->classMask); } } } mouseOn(); } void AGOSEngine::unlinkItem(Item *item) { Item *first, *parent, *next; // can't unlink item without parent if (item->parent == 0) return; // get parent and first child of parent parent = derefItem(item->parent); first = derefItem(parent->child); // the node to remove is first in the parent's children? if (first == item) { parent->child = item->next; item->parent = 0; item->next = 0; return; } for (;;) { if (!first) error("unlinkItem: parent empty"); if (first->next == 0) error("unlinkItem: parent does not contain child"); next = derefItem(first->next); if (next == item) { first->next = next->next; item->parent = 0; item->next = 0; return; } first = next; } } void AGOSEngine::linkItem(Item *item, Item *parent) { uint id; // Don't allow that an item that is already linked is relinked if (item->parent) return; id = itemPtrToID(parent); item->parent = id; if (parent != 0) { item->next = parent->child; parent->child = itemPtrToID(item); } else { item->next = 0; } } int AGOSEngine::wordMatch(Item *item, int16 a, int16 n) { if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) { if (a == -1 && n == -1) return 1; } if (a == -1 && n == item->noun) return 1; if (a == item->adjective && n == item->noun) return 1; return 0; } Item *AGOSEngine::derefItem(uint item) { if (item >= _itemArraySize) error("derefItem: invalid item %d", item); return _itemArrayPtr[item]; } Item *AGOSEngine::findInByClass(Item *i, int16 m) { i = derefItem(i->child); while (i) { if (i->classFlags & m) { _findNextPtr = derefItem(i->next); return i; } if (m == 0) { _findNextPtr = derefItem(i->next); return i; } i = derefItem(i->next); } return NULL; } Item *AGOSEngine::nextInByClass(Item *i, int16 m) { i = _findNextPtr; while (i) { if (i->classFlags & m) { _findNextPtr = derefItem(i->next); return i; } if (m == 0) { _findNextPtr = derefItem(i->next); return i; } i = derefItem(i->next); } return NULL; } Item *AGOSEngine::findMaster(int16 a, int16 n) { uint j; for (j = 1; j < _itemArraySize; j++) { Item *item = derefItem(j); if (item == NULL) continue; if (wordMatch(item, a, n)) return item; } return NULL; } Item *AGOSEngine::nextMaster(Item *i, int16 a, int16 n) { uint j; uint first = itemPtrToID(i) + 1; for (j = first; j < _itemArraySize; j++) { Item *item = derefItem(j); if (item == NULL) continue; if (wordMatch(item, a, n)) return item; } return NULL; } uint AGOSEngine::itemPtrToID(Item *id) { uint i; for (i = 0; i != _itemArraySize; i++) if (_itemArrayPtr[i] == id) return i; error("itemPtrToID: not found"); return 0; // for compilers that don't support NORETURN } } // End of namespace AGOS