diff options
author | Ludvig Strigeus | 2001-10-09 14:30:12 +0000 |
---|---|---|
committer | Ludvig Strigeus | 2001-10-09 14:30:12 +0000 |
commit | c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e (patch) | |
tree | 192b56f3908880c5a513a366f616341bcb47056e /object.cpp | |
download | scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.tar.gz scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.tar.bz2 scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.zip |
Initial revision
svn-id: r3408
Diffstat (limited to 'object.cpp')
-rw-r--r-- | object.cpp | 584 |
1 files changed, 584 insertions, 0 deletions
diff --git a/object.cpp b/object.cpp new file mode 100644 index 0000000000..6590d0ffaa --- /dev/null +++ b/object.cpp @@ -0,0 +1,584 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Change Log: + * $Log$ + * Revision 1.1 2001/10/09 14:30:14 strigeus + * Initial revision + * + * + */ + +#include "stdafx.h" +#include "scumm.h" + +bool Scumm::getClass(int obj, int cls) { + checkRange(_maxNrObjects-1, 0, obj, "Object %d out of range in getClass"); + + cls &= 0x7F; + checkRange(32,1,cls,"Class %d out of range in getClass"); + + return (_classData[obj] & (1<<(cls-1))) != 0; +} + +void Scumm::putClass(int obj, int cls, bool set) { + checkRange(_maxNrObjects-1, 0, obj, "Object %d out of range in getClass"); + + cls &= 0x7F; + checkRange(32,1,cls,"Class %d out of range in getClass"); + + if (set) + _classData[obj] |= (1<<(cls-1)); + else + _classData[obj] &= ~(1<<(cls-1)); +} + +int Scumm::getOwner(int obj) { + checkRange(_maxNrObjects-1, 0, obj, "Object %d out of range in getOwner"); + return _objectFlagTable[obj]&0xF; +} + +void Scumm::putOwner(int act, int owner) { + checkRange(_maxNrObjects-1, 0, act, "Object %d out of range in putOwner"); + checkRange(15, 0, owner, "Owner %d out of range in putOwner"); + _objectFlagTable[act] = (_objectFlagTable[act]&0xF0) | owner; +} + +int Scumm::getState(int act) { + checkRange(_maxNrObjects-1, 0, act, "Object %d out of range in getState"); + return _objectFlagTable[act]>>4; +} + +void Scumm::putState(int act, int state) { + checkRange(_maxNrObjects-1, 0, act, "Object %d out of range in putState"); + checkRange(15, 0, state, "State %d out of range in putState"); + _objectFlagTable[act] = (_objectFlagTable[act]&0x0F) | (state<<4); +} + +int Scumm::getObjectIndex(int object) { + int i; + + if ((_objectFlagTable[object]&0xF)!=0xF) { + for (i=0; i<_maxInventoryItems; i++) + if (_inventory[i] == object) + return i; + return -1; + } else { + for (i=_numObjectsInRoom; i>0; i--) { + if (objs[i].obj_nr==object) + return i; + } + return -1; + } +} + +int Scumm::whereIsObject(int object) { + int i; + + if ((_objectFlagTable[object]&0xF)!=0xF) { + for (i=0; i<_maxInventoryItems; i++) + if (_inventory[i] == object) + return 0; + return -1; + } + + for (i=_numObjectsInRoom; i>0; i--) + if (objs[i].obj_nr == object) { + if (objs[i].fl_object_index) + return 4; + return 1; + } + return -1; +} + +int Scumm::getObjectOrActorXY(int object) { + if (object <= vm.vars[VAR_NUM_ACTOR]) { + return getActorXYPos(derefActorSafe(object, "getObjectOrActorXY")); + } + switch(whereIsObject(object)) { + case -1: + return -1; + case 0: + return getActorXYPos(derefActorSafe(_objectFlagTable[object]&0xF,"getObjectOrActorXY(2)")); + } + getObjectXYPos(object); + return 0; +} + +void Scumm::getObjectXYPos(int object) { + ObjectData *od = &objs[getObjectIndex(object)]; + AdjustBoxResult abr; + abr = adjustXYToBeInBox(0, od->cdhd_10, od->cdhd_12); + _xPos = abr.x; + _yPos = abr.y; + _dir = od->actordir&3; +} + +int Scumm::getObjActToObjActDist(int a, int b) { + int x,y; + Actor *acta = NULL; + Actor *actb = NULL; + + if (a<=vm.vars[VAR_NUM_ACTOR]) + acta = derefActorSafe(a, "getObjActToObjActDist"); + + if (b<=vm.vars[VAR_NUM_ACTOR]) + actb = derefActorSafe(b, "getObjActToObjActDist(2)"); + + if (acta && actb && acta->room==actb->room && acta->room && + acta->room != _currentRoom) + return 0xFF; + + if (getObjectOrActorXY(a)==-1) + return 0xFF; + + x = _xPos; + y = _yPos; + + if (getObjectOrActorXY(b)==-1) + return 0xFF; + + /* XXX: bug here? should be <= */ + if (acta) { + AdjustBoxResult r = adjustXYToBeInBox(acta, _xPos, _yPos); + _xPos = r.x; + _yPos = r.y; + } + + y = abs(y-_yPos); + x = abs(x-_xPos); + + if (y>x) x=y; + return x; +} + +int Scumm::findObject(int x, int y) { + int i,a,b; + + for (i=1; i<=_numObjectsInRoom; i++) { + if (!objs[i].obj_nr || getClass(objs[i].obj_nr, 32)) + continue; + b = i; + do { + a = objs[b].cdhd_0e; + b = objs[b].cdhd_0f; + if (b==0) { + if (objs[i].x_pos <= (x>>3) && + objs[i].numstrips + objs[i].x_pos > (x>>3) && + objs[i].y_pos <= (y>>3) && + objs[i].height + objs[i].y_pos > (y>>3)) + return objs[i].obj_nr; + break; + } + } while ( (objs[b].ownerstate&0xF0) == a); + } + return 0; +} + +void Scumm::drawRoomObjects(int arg) { + int num = _numObjectsInRoom; + ObjectData *od; + int a; + + if (num==0) + return; + + do { + od = &objs[num]; + if (!od->obj_nr || !(od->ownerstate&0xF0)) + continue; + + do { + a = od->cdhd_0e; + if (!od->cdhd_0f) { + drawObject(num, arg); + break; + } + od = &objs[od->cdhd_0f]; + } while ((od->ownerstate & 0xF0)==a); + + } while (--num); +} + +const uint32 state_tags[] = { + MKID('IM00'), + MKID('IM01'), + MKID('IM02'), + MKID('IM03'), + MKID('IM04'), + MKID('IM05'), + MKID('IM06'), + MKID('IM07'), + MKID('IM08'), + MKID('IM09'), + MKID('IM0A'), + MKID('IM0B'), + MKID('IM0C'), + MKID('IM0D'), + MKID('IM0E'), + MKID('IM0F') +}; + +void Scumm::drawObject(int obj, int arg) { + ObjectData *od; + int xpos, ypos, height, width; + byte *ptr; + int x,a,b; + + if (_BgNeedsRedraw) + arg = 0; + + gdi.virtScreen = 0; + + od = &objs[obj]; + + xpos = od->x_pos; + ypos = od->y_pos; + width = od->numstrips; + height = od->height; + + if (width==0 || xpos > _screenEndStrip || xpos + width < _screenStartStrip) + return; + + if (od->fl_object_index) { + ptr = getResourceAddress(0xD, od->fl_object_index); + ptr = findResource(MKID('OBIM'), ptr); + } else { + ptr = getResourceAddress(1, _roomResource); + ptr = ptr + od->offs_obim_to_room; + } + + ptr = findResource(state_tags[getState(od->obj_nr)], ptr); + if (!ptr) + return; + + x = 0xFFFF; + + for (a=b=0; a<width; a++) { + _drawBmpX = xpos + a; + if (arg==1 && _screenStartStrip!=_drawBmpX) + continue; + if (arg==2 && _screenEndStrip!=_drawBmpX) + continue; + if (_screenStartStrip > _drawBmpX || _drawBmpX > _screenEndStrip) + continue; + actorDrawBits[_drawBmpX] |= 0x8000; + if (_drawBmpX < x) + x = _drawBmpX; + b++; + } + + if (b==0) + return; + + _drawBmpY = ypos << 3; + gdi.numLinesToProcess = height << 3; + + _drawBmpX = x; + drawBmp(ptr, x - xpos, b, 1, "Object", od->obj_nr); +} + +void Scumm::loadRoomObjects() { + int i,j; + ObjectData *od; + byte *ptr; + uint16 obim_id; + byte *room,*tmp_room; + ImageHeader *imhd; + RoomHeader *roomhdr; + + CodeHeader *cdhd; + + checkHeap(); + + room = getResourceAddress(1, _roomResource); + roomhdr = (RoomHeader*)findResource(MKID('RMHD'), room); + + _numObjectsInRoom = READ_LE_UINT16(&roomhdr->numObjects); + + if (_numObjectsInRoom == 0) + return; + + if (_numObjectsInRoom > 200) + error("More than %d objects in room %d", 200, _roomResource); + + tmp_room = room; + + od = &objs[1]; + for (i=1; i<=_numObjectsInRoom; i++,od++) { + ptr = findResource(MKID('OBCD'), tmp_room); + if (ptr==NULL) + error("Room %d missing object code block(s)", _roomResource); + + od->offs_obcd_to_room = ptr - room; + cdhd = (CodeHeader*)findResource2(MKID('CDHD'), ptr); + od->obj_nr = READ_LE_UINT16(&cdhd->obj_id); + +#ifdef DUMP_SCRIPTS + do { + char buf[32]; + sprintf(buf,"roomobj-%d-",_roomResource); + dumpResource(buf, od->obj_nr, ptr); + } while (0); +#endif + tmp_room = NULL; + } + + tmp_room = room; + for (i=1; i<=_numObjectsInRoom; i++) { + ptr = findResource(MKID('OBIM'), tmp_room); + if (ptr==NULL) + error("Room %d missing image blocks(s)", _roomResource); + + imhd = (ImageHeader*)findResource2(MKID('IMHD'), ptr); + obim_id = READ_LE_UINT16(&imhd->obj_id); + + for(j=1; j<=_numObjectsInRoom; j++) { + if (objs[j].obj_nr==obim_id) + objs[j].offs_obim_to_room = ptr - room; + } + tmp_room = NULL; + } + + od = &objs[1]; + for (i=1; i<=_numObjectsInRoom; i++,od++) { + ptr = room + objs[i].offs_obcd_to_room; + cdhd = (CodeHeader*)findResource2(MKID('CDHD'), ptr); + objs[i].obj_nr = READ_LE_UINT16(&cdhd->obj_id); + objs[i].numstrips = cdhd->w; + objs[i].height = cdhd->h; + objs[i].x_pos = cdhd->x; + objs[i].y_pos = cdhd->y; + + if (!(cdhd->flags&0x80)) { + objs[i].cdhd_0e = 0x10; + } else { + objs[i].cdhd_0e = cdhd->flags; + } + objs[i].cdhd_0f = cdhd->unk1; + objs[i].cdhd_10 = READ_LE_UINT16(&cdhd->unk2); + objs[i].cdhd_12 = READ_LE_UINT16(&cdhd->unk3); + objs[i].actordir = cdhd->unk4; + objs[i].fl_object_index = 0; + } + + checkHeap(); +} + +void Scumm::fixObjectFlags() { + int i; + ObjectData *od = &objs[1]; + for (i=1; i<=_numObjectsInRoom; i++,od++) { + od->ownerstate = _objectFlagTable[od->obj_nr]; + } +} + +void Scumm::processDrawQue() { + int i, j; + for (i=0; i<_drawObjectQueNr; i++) { + j = _drawObjectQue[i]; + if (j) + drawObject(j,0); + } + _drawObjectQueNr = 0; +} + +void Scumm::clearOwnerOf(int obj) { + int i,j; + uint16 *a; + byte *ptr; + + stopObjectScript(obj); + + if (getOwner(obj)==0xF) { + i = 0; + do { + if (objs[i].obj_nr==obj) { + if (!objs[i].fl_object_index) + return; + nukeResource(0xD, objs[i].fl_object_index); + objs[i].obj_nr = 0; + objs[i].fl_object_index = 0; + } + } while(++i <= _numObjectsInRoom); + return; + } + for (i=1; i<_maxInventoryItems; i++) { + if (_inventory[i] == obj) { + j = whereIsObject(obj); + if (j==0) { + nukeResource(5, i); + _inventory[i] = 0; + } + a = &_inventory[2]; + for (i=1; i < _maxInventoryItems-1; i++) { + if (!a[-1] && a[0]) { + a[-1] = a[0]; + ptr = getResourceAddress(5, i+1); + _baseInventoryItems[i] = _baseInventoryItems[i+1]; + /* TODO: some wacky write is done here */ + error("clearOwnerOf: not fully implemented"); + } + } + return; + } + } +} + +void Scumm::removeObjectFromRoom(int obj) { + int i,cnt; + uint16 *ptr; + + for(i=1; i<=_numObjectsInRoom; i++) { + if (objs[i].obj_nr==obj) { + if (objs[i].numstrips != 0) { + ptr = &actorDrawBits[objs[i].x_pos]; + cnt = objs[i].numstrips; + do { + *ptr++ |= 0x8000; + } while (--cnt); + } + _BgNeedsRedraw = 1; + return; + } + } +} + +void Scumm::addObjectToDrawQue(int object) { + _drawObjectQue[_drawObjectQueNr++] = object; + if (_drawObjectQueNr > 200) + error("Draw Object Que overflow"); +} + +void Scumm::clearDrawObjectQueue() { + _drawObjectQueNr = 0; +} + +byte *Scumm::getObjOrActorName(int obj) { + byte *objptr; + + if (obj <= vm.vars[VAR_NUM_ACTOR]) + return getActorName(derefActorSafe(obj, "getObjOrActorName")); + + objptr = getObjectAddress(obj); + if (objptr==NULL) + return (byte*)" "; + + return findResource(MKID('OBNA'), objptr) + 8; +} + +uint32 Scumm::getOBCDOffs(int object) { + int i; + + if ((_objectFlagTable[object]&0xF)!=0xF) + return 0; + for (i=_numObjectsInRoom; i>0; i--) { + if (objs[i].obj_nr == object) { + if (objs[i].fl_object_index!=0) + return 8; + return objs[i].offs_obcd_to_room; + } + } + return 0; +} + +byte *Scumm::getObjectAddress(int obj) { + int i; + + if ((_objectFlagTable[obj]&0xF)!=0xF) { + for(i=0; i<_maxInventoryItems; i++) { + if (_inventory[i] == obj) + return getResourceAddress(5, i); + } + } else { + for(i=_numObjectsInRoom; i>0; --i) { + if (objs[i].obj_nr==obj) { + if (objs[i].fl_object_index) + return getResourceAddress(0xD, objs[i].fl_object_index)+8; + return getResourceAddress(1, _roomResource) + objs[i].offs_obcd_to_room; + } + } + } + return 0; +} + +void Scumm::addObjectToInventory(int obj, int room) { + int i, slot; + byte *ptr,*obcdptr; + uint32 size,cdoffs; + int numobj; + byte *tmp_roomptr,*roomptr; + CodeHeader *cdhd; + RoomHeader *roomhdr; + + debug(1,"Adding object %d from room %d into inventory", obj, room); + + checkHeap(); + + if (whereIsObject(obj)==4) { + i = getObjectIndex(obj); + ptr = getResourceAddress(0xD, objs[i].fl_object_index) + 64; + size = READ_BE_UINT32_UNALIGNED(ptr+4); + slot = getInventorySlot(); + _inventory[slot] = obj; + createResource(5, slot, size); + ptr = getResourceAddress(0xD, objs[i].fl_object_index) + 64; + memcpy(getResourceAddress(5, slot), ptr, size); + checkHeap(); + return; + } + ensureResourceLoaded(1, room); + roomptr = getResourceAddress(1, room); + roomhdr = (RoomHeader*)findResource(MKID('RMHD'), roomptr); + numobj = READ_LE_UINT16(&roomhdr->numObjects); + if (numobj==0) + error("addObjectToInventory: No object found in room %d", room); + if (numobj > 200) + error("addObjectToInventory: More (%d) than %d objects in room %d", numobj, 200, room); + + tmp_roomptr = roomptr; + for (i=1; i<=numobj; i++) { + obcdptr = findResource(MKID('OBCD'), tmp_roomptr); + if(obcdptr==NULL) + error("addObjectToInventory: Not enough code blocks in room %d", room); + cdhd = (CodeHeader*)findResource2(MKID('CDHD'), obcdptr); + if ( READ_LE_UINT16(&cdhd->obj_id) == obj) { + cdoffs = obcdptr - roomptr; + size = READ_BE_UINT32_UNALIGNED(obcdptr+4); + slot = getInventorySlot(); + _inventory[slot] = obj; + createResource(5, slot, size); + obcdptr = getResourceAddress(1, room) + cdoffs; + memcpy(getResourceAddress(5,slot),obcdptr,size); + checkHeap(); + return; + } + tmp_roomptr = NULL; + } + + error("addObjectToInventory: Object %d not found in room %d", obj, room); +} + +int Scumm::getInventorySlot() { + int i; + for (i=1; i<=_maxInventoryItems; i++) { + if (_inventory[i]==0) + return i; + } + error("Inventory full, %d max items", _maxInventoryItems); +} + |