scummvm/object.cpp
James Brown 0b02fccef0 Zak256 object image fix!
svn-id: r3596
2002-02-15 21:17:42 +00:00

1203 lines
30 KiB
C++

/* 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.
*
* $Header$
*
*/
#include "stdafx.h"
#include "scumm.h"
bool Scumm::getClass(int obj, int cls) {
checkRange(_numGlobalObjects-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(_numGlobalObjects-1, 0, obj, "Object %d out of range in putClass");
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(_numGlobalObjects-1, 0, obj, "Object %d out of range in getOwner");
return _objectOwnerTable[obj];
}
void Scumm::putOwner(int act, int owner) {
checkRange(_numGlobalObjects-1, 0, act, "Object %d out of range in putOwner");
checkRange(0xFF, 0, owner, "Owner %d out of range in putOwner");
_objectOwnerTable[act] = owner;
}
int Scumm::getState(int act) {
checkRange(_numGlobalObjects-1, 0, act, "Object %d out of range in getState");
return _objectStateTable[act];
}
void Scumm::putState(int act, int state) {
checkRange(_numGlobalObjects-1, 0, act, "Object %d out of range in putState");
checkRange(0xFF, 0, state, "State %d out of range in putState");
_objectStateTable[act] = state;
}
int Scumm::getObjectRoom(int obj) {
checkRange(_numGlobalObjects-1, 0, obj, "Object %d out of range in getObjectRoom");
return _objectRoomTable[obj];
}
int Scumm::getObjectIndex(int object) {
int i;
/* OF_OWNER_ROOM should be 0xFF for full throttle, else 0xF */
if (_objectOwnerTable[object] != OF_OWNER_ROOM) {
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 (object >= _numGlobalObjects)
return WIO_NOT_FOUND;
if (_objectOwnerTable[object] != OF_OWNER_ROOM) {
for (i=0; i<_maxInventoryItems; i++)
if (_inventory[i] == object)
return WIO_INVENTORY;
return WIO_NOT_FOUND;
}
for (i=_numObjectsInRoom; i>0; i--)
if (_objs[i].obj_nr == object) {
if (_objs[i].fl_object_index)
return WIO_FLOBJECT;
return WIO_ROOM;
}
return WIO_NOT_FOUND;
}
int Scumm::getObjectOrActorXY(int object) {
if (object < NUM_ACTORS) {
return getActorXYPos(derefActorSafe(object, "getObjectOrActorXY"));
}
switch(whereIsObject(object)) {
case WIO_NOT_FOUND:
return -1;
case WIO_INVENTORY:
return getActorXYPos(derefActorSafe(_objectOwnerTable[object],"getObjectOrActorXY(2)"));
}
getObjectXYPos(object);
return 0;
}
/* Return the position of an object.
Returns X, Y and direction in angles
*/
void Scumm::getObjectXYPos(int object) {
ObjectData *od = &_objs[getObjectIndex(object)];
int state;
byte *ptr;
ImageHeader *imhd;
int x,y;
AdjustBoxResult abr;
if(!(_features & GF_SMALL_HEADER)) {
if (_features&GF_AFTER_V6) {
state = getState(object)-1;
if (state<0)
state = 0;
if (od->fl_object_index) {
ptr = getResourceAddress(rtFlObject, od->fl_object_index);
ptr = findResource(MKID('OBIM'), ptr);
} else {
ptr = getResourceAddress(rtRoom, _roomResource);
ptr += od->offs_obim_to_room;
}
assert(ptr);
imhd = (ImageHeader*)findResourceData(MKID('IMHD'), ptr);
x = od->x_pos + (int16)READ_LE_UINT16(&imhd->hotspot[state].x);
y = od->y_pos + (int16)READ_LE_UINT16(&imhd->hotspot[state].y);
} else {
x = (int16)READ_LE_UINT16(&od->walk_x);
y = (int16)READ_LE_UINT16(&od->walk_y);
}
_xPos = x;
_yPos = y;
_dir = oldDirToNewDir(od->actordir&3);
} else {
x = (int16)READ_LE_UINT32(&od->walk_x);
y = (int16)READ_LE_UINT16(&od->walk_y);
_xPos = x;
_yPos = y;
_dir= oldDirToNewDir(od->actordir&3);
}
// abr = adjustXYToBeInBox(0, x, y);
// _xPos = abr.x;
// _yPos = abr.y;
// _xPos = x;
// _yPos = y;
// _dir = oldDirToNewDir(od->actordir&3);
}
int Scumm::getObjActToObjActDist(int a, int b) {
int x,y;
Actor *acta = NULL;
Actor *actb = NULL;
if (a<NUM_ACTORS)
acta = derefActorSafe(a, "getObjActToObjActDist");
if (b<NUM_ACTORS)
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;
if (acta) {
AdjustBoxResult r = adjustXYToBeInBox(acta, _xPos, _yPos, 0);
_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,b;
byte a;
for (i=1; i<=_numObjectsInRoom; i++) {
if (!_objs[i].obj_nr || getClass(_objs[i].obj_nr, 32))
continue;
b = i;
do {
a = _objs[b].parentstate;
b = _objs[b].parent;
if (b==0) {
if (_objs[i].x_pos <= x &&
_objs[i].width + _objs[i].x_pos > x &&
_objs[i].y_pos <= y &&
_objs[i].height + _objs[i].y_pos > y)
return _objs[i].obj_nr;
break;
}
} while ( _objs[b].state == a);
}
return 0;
}
void Scumm::drawRoomObject(int i, int arg) {
ObjectData *od;
byte a;
od = &_objs[i];
if (!od->obj_nr || !od->state)
return;
do {
a = od->parentstate;
if (!od->parent) {
drawObject(i, arg);
break;
}
od = &_objs[od->parent];
} while (od->state==a);
}
void Scumm::drawRoomObjects(int arg) {
int i;
if (_features & GF_DRAWOBJ_OTHER_ORDER) {
for(i=1; i<=_numObjectsInRoom; i++)
drawRoomObject(i,arg);
} else {
for(i=_numObjectsInRoom; i!=0; i--)
drawRoomObject(i,arg);
}
}
const uint32 IMxx_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,numstrip;
int tmp;
if (_BgNeedsRedraw)
arg = 0;
_curVirtScreen = &virtscr[0];
od = &_objs[obj];
xpos = od->x_pos>>3;
ypos = od->y_pos;
width = od->width>>3;
height = od->height &= 0xF8; // Ender
if (width==0 || xpos > _screenEndStrip || xpos + width < _screenStartStrip)
return;
if (od->fl_object_index) {
ptr = getResourceAddress(rtFlObject, od->fl_object_index);
ptr = findResource(MKID('OBIM'), ptr);
} else {
ptr = getResourceAddress(rtRoom, _roomResource);
ptr = ptr + od->offs_obim_to_room;
}
if(_features & GF_SMALL_HEADER)
ptr +=8;
else
ptr = findResource(IMxx_tags[getState(od->obj_nr)], ptr);
if (!ptr)
return;
x = 0xFFFF;
for (a=numstrip=0; a<width; a++) {
tmp = xpos + a;
if (arg==1 && _screenStartStrip!=tmp)
continue;
if (arg==2 && _screenEndStrip!=tmp)
continue;
if (tmp < _screenStartStrip || tmp > _screenEndStrip)
continue;
gfxUsageBits[tmp] |= 0x80000000;
if (tmp < x)
x = tmp;
numstrip++;
}
if (numstrip!=0) {
byte flags = Gdi::dbAllowMaskOr;
if (_features&GF_AFTER_V7 && getClass(od->obj_nr, 22))
flags |= Gdi::dbDrawMaskOnBoth;
gdi.drawBitmap(ptr, _curVirtScreen, x, ypos, height, x-xpos, numstrip, flags);
}
}
void Scumm::loadRoomObjects() {
int i,j;
ObjectData *od;
byte *ptr;
uint16 obim_id;
byte *room,*searchptr;
ImageHeader *imhd;
RoomHeader *roomhdr;
CodeHeader *cdhd;
CHECK_HEAP
room = getResourceAddress(rtRoom, _roomResource);
roomhdr = (RoomHeader*)findResourceData(MKID('RMHD'), room);
_numObjectsInRoom = READ_LE_UINT16(&roomhdr->numObjects);
if (_numObjectsInRoom == 0)
return;
if (_numObjectsInRoom > _numLocalObjects)
error("More than %d objects in room %d", _numLocalObjects, _roomResource);
od = &_objs[1];
searchptr = room;
for (i=0; i<_numObjectsInRoom; i++,od++) {
ptr = findResource(MKID('OBCD'), searchptr);
if (ptr==NULL)
error("Room %d missing object code block(s)", _roomResource);
od->offs_obcd_to_room = ptr - room;
cdhd = (CodeHeader*)findResourceData(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
searchptr = NULL;
}
searchptr = room;
for (i=0; i<_numObjectsInRoom; i++) {
ptr = findResource(MKID('OBIM'), searchptr);
if (ptr==NULL)
error("Room %d missing image blocks(s)", _roomResource);
imhd = (ImageHeader*)findResourceData(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;
}
searchptr = NULL;
}
od = &_objs[1];
for (i=1; i<=_numObjectsInRoom; i++,od++) {
setupRoomObject(od, room);
}
CHECK_HEAP
}
void Scumm::loadRoomObjectsSmall() {
int i,j;
ObjectData *od;
byte *ptr;
uint16 obim_id;
byte *room,*searchptr;
ImageHeader *imhd;
RoomHeader *roomhdr;
CodeHeader *cdhd;
CHECK_HEAP
room = getResourceAddress(rtRoom, _roomResource);
roomhdr = (RoomHeader*)findResourceData(MKID('RMHD'), room);
_numObjectsInRoom = READ_LE_UINT16(&roomhdr->numObjects);
if (_numObjectsInRoom == 0)
return;
if (_numObjectsInRoom > _numLocalObjects)
error("More than %d objects in room %d", _numLocalObjects, _roomResource);
od = &_objs[1];
searchptr = room;
for (i=0; i<_numObjectsInRoom; i++,od++) {
ptr = findResourceSmall(MKID('OBCD'), searchptr);
if (ptr==NULL)
error("Room %d missing object code block(s)", _roomResource);
od->offs_obcd_to_room = ptr - room;
od->obj_nr = READ_LE_UINT16(ptr+6);
#ifdef DUMP_SCRIPTS
do {
char buf[32];
sprintf(buf,"roomobj-%d-",_roomResource);
dumpResource(buf, od->obj_nr, ptr);
} while (0);
#endif
searchptr = NULL;
}
searchptr = room;
for (i=0; i<_numObjectsInRoom; i++) {
ptr = findResourceSmall(MKID('OBIM'), searchptr);
if (ptr==NULL)
error("Room %d missing image blocks(s)", _roomResource);
obim_id = READ_LE_UINT16(ptr+6);
for(j=1; j<=_numObjectsInRoom; j++) {
if (_objs[j].obj_nr==obim_id)
_objs[j].offs_obim_to_room = ptr - room;
}
searchptr = NULL;
}
od = &_objs[1];
for (i=1; i<=_numObjectsInRoom; i++,od++) {
setupRoomObject(od, room);
}
CHECK_HEAP
}
void Scumm::setupRoomObject(ObjectData *od, byte *room) {
byte *obcd;
CodeHeader *cdhd;
ImageHeader *imhd;
if(_features & GF_SMALL_HEADER) {
byte *ptr = room + od->offs_obcd_to_room;
od->obj_nr = READ_LE_UINT16(ptr+6); // ok
od->width = *(ptr+11)<<3; // ok
od->x_pos = *(ptr+9)<<3; // ok
if(*(ptr+10) & 0x80) {
od->parentstate = 1; // it's 0x10 in the original code
} else {
od->parentstate = 0;
}
od->y_pos = ((*(ptr+10))&0x7F)<<3;
od->parent = *(ptr+12);
od->walk_x = READ_LE_UINT16(ptr+13);
od->walk_y = READ_LE_UINT16(ptr+15);
od->actordir = (*(ptr+17))&7;
od->height = *(ptr+17); // ok
return;
}
cdhd = (CodeHeader*)findResourceData(MKID('CDHD'), room + od->offs_obcd_to_room);
od->obj_nr = READ_LE_UINT16(&cdhd->obj_id);
#if !defined(FULL_THROTTLE)
if (_features & GF_AFTER_V6) {
od->width = READ_LE_UINT16(&cdhd->v6.w);
od->height = READ_LE_UINT16(&cdhd->v6.h);
od->x_pos = ((int16)READ_LE_UINT16(&cdhd->v6.x));
od->y_pos = ((int16)READ_LE_UINT16(&cdhd->v6.y));
if (cdhd->v6.flags == 0x80) {
od->parentstate = 1;
} else {
od->parentstate = (cdhd->v6.flags&0xF);
}
od->parent = cdhd->v6.parent;
od->actordir = cdhd->v6.actordir;
} else {
od->width = cdhd->v5.w<<3;
od->height = cdhd->v5.h<<3;
od->x_pos = cdhd->v5.x<<3;
od->y_pos = cdhd->v5.y<<3;
if (cdhd->v5.flags == 0x80) {
od->parentstate = 1;
} else {
od->parentstate = (cdhd->v5.flags&0xF);
}
od->parent = cdhd->v5.parent;
od->walk_x = READ_LE_UINT16(&cdhd->v5.walk_x);
od->walk_y = READ_LE_UINT16(&cdhd->v5.walk_y);
od->actordir = cdhd->v5.actordir;
}
#else
od->parent = cdhd->parent;
od->parentstate = cdhd->parentstate;
imhd = (ImageHeader*)findResourceData(MKID('IMHD'), room + od->offs_obim_to_room);
od->x_pos = imhd->x_pos;
od->y_pos = imhd->y_pos;
od->width = imhd->width;
od->height = imhd->height;
od->actordir = imhd->actordir;
#endif
od->fl_object_index = 0;
}
void Scumm::fixObjectFlags() {
int i;
ObjectData *od = &_objs[1];
for (i=1; i<=_numObjectsInRoom; i++,od++) {
od->state = _objectStateTable[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)==OF_OWNER_ROOM) {
i = 0;
do {
if (_objs[i].obj_nr==obj) {
if (!_objs[i].fl_object_index)
return;
nukeResource(rtFlObject, _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==WIO_INVENTORY) {
nukeResource(rtInventory, i);
_inventory[i] = 0;
}
a = &_inventory[1];
for (i=1; i < _maxInventoryItems-1; i++,a++) {
if (!a[0] && a[1]) {
a[0] = a[1];
a[1] = 0;
_baseInventoryItems[i] = _baseInventoryItems[i+1];
_baseInventoryItems[i+1] = NULL;
}
}
return;
}
}
}
void Scumm::removeObjectFromRoom(int obj) {
int i,cnt;
uint32 *ptr;
for(i=1; i<=_numObjectsInRoom; i++) {
if (_objs[i].obj_nr==(uint16)obj) {
if (_objs[i].width != 0) {
ptr = &gfxUsageBits[_objs[i].x_pos>>3];
cnt = _objs[i].width>>3;
do {
*ptr++ |= 0x80000000;
} while (--cnt);
}
_BgNeedsRedraw = true;
return;
}
}
}
void Scumm::addObjectToDrawQue(int object) {
_drawObjectQue[_drawObjectQueNr++] = object;
if (_drawObjectQueNr > sizeof(_drawObjectQue)/sizeof(_drawObjectQue[0]))
error("Draw Object Que overflow");
}
void Scumm::clearDrawObjectQueue() {
_drawObjectQueNr = 0;
}
byte *Scumm::getObjOrActorName(int obj) {
byte *objptr;
if (obj < NUM_ACTORS)
return getActorName(derefActorSafe(obj, "getObjOrActorName"));
if(_features & GF_SMALL_HEADER) {
byte offset;
objptr = getOBCDFromObject(obj);
offset = *(objptr+18);
return(objptr+offset);
}
objptr = getOBCDFromObject(obj);
if (objptr==NULL)
return (byte*)" ";
return findResourceData(MKID('OBNA'), objptr);
}
uint32 Scumm::getOBCDOffs(int object) {
int i;
if (_objectOwnerTable[object] != OF_OWNER_ROOM)
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::getOBCDFromObject(int obj) {
int i;
if (_objectOwnerTable[obj] != OF_OWNER_ROOM) {
for(i=0; i<_maxInventoryItems; i++) {
if (_inventory[i] == obj)
return getResourceAddress(rtInventory, i);
}
} else {
for(i=_numObjectsInRoom; i>0; --i) {
if (_objs[i].obj_nr==obj) {
if (_objs[i].fl_object_index)
return getResourceAddress(rtFlObject, _objs[i].fl_object_index)+8;
return getResourceAddress(rtRoom, _roomResource) + _objs[i].offs_obcd_to_room;
}
}
}
return 0;
}
void Scumm::addObjectToInventory(uint obj, uint room) {
int i, slot;
uint32 size;
byte *obcdptr,*ptr;
FindObjectInRoom foir;
debug(1,"Adding object %d from room %d into inventory", obj, room);
CHECK_HEAP
if (whereIsObject(obj)==WIO_FLOBJECT) {
i = getObjectIndex(obj);
ptr = getResourceAddress(rtFlObject, _objs[i].fl_object_index) + 8;
size = READ_BE_UINT32_UNALIGNED(ptr+4);
slot = getInventorySlot();
_inventory[slot] = obj;
createResource(rtInventory, slot, size);
ptr = getResourceAddress(rtFlObject, _objs[i].fl_object_index) + 8;
memcpy(getResourceAddress(rtInventory, slot), ptr, size);
} else {
findObjectInRoom(&foir, foCodeHeader, obj, room);
if(_features & GF_SMALL_HEADER )
size = READ_LE_UINT32(foir.obcd);
else
size = READ_BE_UINT32_UNALIGNED(foir.obcd+4);
slot = getInventorySlot();
_inventory[slot] = obj;
createResource(rtInventory, slot, size);
obcdptr = getResourceAddress(rtRoom, room) - foir.roomptr + foir.obcd;
memcpy(getResourceAddress(rtInventory,slot),obcdptr,size);
}
CHECK_HEAP
}
void Scumm::findObjectInRoom(FindObjectInRoom *fo, byte findWhat, uint id, uint room) {
CodeHeader *cdhd;
int i, numobj;
byte *roomptr,*obcdptr,*obimptr,*searchptr;
RoomHeader *roomhdr;
ImageHeader *imhd;
if (findWhat&foCheckAlreadyLoaded && getObjectIndex(id) != -1) {
fo->obcd = obcdptr = getOBCDFromObject(id);
assert((byte*)obcdptr > (byte*)256);
fo->obim = obimptr = obcdptr + READ_BE_UINT32_UNALIGNED(&((ResHdr*)obcdptr)->size);
fo->cdhd = (CodeHeader*)findResourceData(MKID('CDHD'), obcdptr);
fo->imhd = (ImageHeader*)findResourceData(MKID('IMHD'), obimptr);
return;
}
fo->roomptr = roomptr = getResourceAddress(rtRoom, room);
roomhdr = (RoomHeader*)findResourceData(MKID('RMHD'), roomptr);
numobj = READ_LE_UINT16(&roomhdr->numObjects);
if (numobj==0)
error("findObjectInRoom: No object found in room %d", room);
if (numobj > _numLocalObjects)
error("findObjectInRoom: More (%d) than %d objects in room %d", numobj, _numLocalObjects, room);
if (findWhat & foCodeHeader) {
searchptr = roomptr;
for (i=0;;) {
if(_features & GF_SMALL_HEADER)
obcdptr = findResourceSmall(MKID('OBCD'), searchptr);
else
obcdptr = findResource(MKID('OBCD'), searchptr);
if(obcdptr==NULL)
error("findObjectInRoom: Not enough code blocks in room %d", room);
if ( _features & GF_SMALL_HEADER) {
if ( READ_LE_UINT16(obcdptr+6) == (uint16)id) {
fo->cdhd = NULL;
fo->obcd = obcdptr;
break;
}
} else {
cdhd = (CodeHeader*)findResourceData(MKID('CDHD'), obcdptr);
if ( READ_LE_UINT16(&cdhd->obj_id) == (uint16)id) {
fo->cdhd = cdhd;
fo->obcd = obcdptr;
break;
}
}
if (++i == numobj)
error("findObjectInRoom: Object %d not found in room %d", id, room);
searchptr = NULL;
}
}
if (findWhat & foImageHeader) {
searchptr = roomptr;
for(i=0;;) {
if(_features & GF_SMALL_HEADER)
obimptr = findResourceSmall(MKID('OBIM'), searchptr);
else
obimptr = findResource(MKID('OBIM'), searchptr);
if (obimptr==NULL)
error("findObjectInRoom: Not enough image blocks in room %d", room);
imhd = (ImageHeader*)findResourceData(MKID('IMHD'), obimptr);
if(_features & GF_SMALL_HEADER){
if (READ_LE_UINT16(obimptr+6) == (uint16)id) {
fo->obim = obimptr;
fo->imhd = imhd;
break;
}
} else {
if (READ_LE_UINT16(&imhd->obj_id) == (uint16)id) {
fo->obim = obimptr;
fo->imhd = imhd;
break;
}
}
if (++i==numobj)
error("findObjectInRoom: Object %d image not found in room %d", id, room);
searchptr = NULL;
}
}
}
int Scumm::getInventorySlot() {
int i;
for (i=1; i<=_maxInventoryItems; i++) {
if (_inventory[i]==0)
return i;
}
error("Inventory full, %d max items", _maxInventoryItems);
}
void Scumm::setOwnerOf(int obj, int owner) {
ScriptSlot *ss;
if (owner==0) {
clearOwnerOf(obj);
ss = &vm.slot[_currentScript];
if (ss->where==WIO_INVENTORY && _inventory[ss->number]==obj) {
putOwner(obj, 0);
runHook(0);
stopObjectCode();
return;
}
}
putOwner(obj, owner);
runHook(0);
}
int Scumm::getObjX(int obj) {
if (obj < NUM_ACTORS) {
if (obj==0)
return 0; /* fix for indy4's map */
return derefActorSafe(obj,"getObjX")->x;
} else {
if (whereIsObject(obj)==WIO_NOT_FOUND)
return -1;
getObjectOrActorXY(obj);
return _xPos;
}
}
int Scumm::getObjY(int obj) {
if (obj < NUM_ACTORS) {
if (obj==0)
return 0; /* fix for indy4's map */
return derefActorSafe(obj,"getObjY")->y;
} else {
if (whereIsObject(obj)==WIO_NOT_FOUND)
return -1;
getObjectOrActorXY(obj);
return _yPos;
}
}
int Scumm::getObjOldDir(int obj) {
if (obj < NUM_ACTORS) {
return newDirToOldDir(derefActorSafe(obj,"getObjOldDir")->facing);
} else {
getObjectXYPos(obj);
return _dir;
}
}
int Scumm::getObjNewDir(int obj) {
if (obj < NUM_ACTORS) {
return derefActorSafe(obj,"getObjNewDir")->facing;
} else {
getObjectXYPos(obj);
return oldDirToNewDir(_dir);
}
}
int Scumm::findInventory(int owner, int index) {
int count = 1, i, obj;
for (i=0; i!=_maxInventoryItems; i++) {
obj = _inventory[i];
if (obj && getOwner(obj)==owner && count++ == index)
return obj;
}
return 0;
}
int Scumm::getInventoryCount(int owner) {
int i,obj;
int count = 0;
for (i=0; i!=_maxInventoryItems; i++) {
obj = _inventory[i];
if (obj && getOwner(obj) == owner)
count++;
}
return count;
}
void Scumm::setObjectState(int obj, int state, int x, int y) {
int i;
i = getObjectIndex(obj);
if (i==-1) {
warning("setObjectState: no such object");
return;
}
if (x != -1) {
_objs[i].x_pos = x<<3;
_objs[i].y_pos = y<<3;
}
addObjectToDrawQue(i);
putState(obj, state);
}
static int getDist(int x, int y, int x2, int y2) {
int a = abs(y-y2);
int b = abs(x-x2);
if (a>b)
return a;
return b;
}
int Scumm::getDistanceBetween(bool is_obj_1, int b, int c, bool is_obj_2, int e, int f) {
int i,j;
int x,y;
int x2,y2;
j = i = 0xFF;
if (is_obj_1) {
if (getObjectOrActorXY(b)==-1)
return -1;
if (b < NUM_ACTORS)
i = derefActorSafe(b, "unkObjProc1")->scalex;
x = _xPos;
y = _yPos;
} else {
x = b;
y = c;
}
if (is_obj_2) {
if (getObjectOrActorXY(e)==-1)
return -1;
if (e < NUM_ACTORS)
j = derefActorSafe(e, "unkObjProc1(2)")->scalex;
x2 = _xPos;
y2 = _yPos;
} else {
x2 = e;
y2 = f;
}
return getDist(x,y,x2,y2) * 0xFF / ((i + j)>>1);
}
void Scumm::setCursorImg(uint img, uint room, uint imgindex) {
byte *ptr;
int index;
int w,h;
byte *roomptr,*obim,*dataptr,*bomp;
RoomHeader *rmhd;
int i,numobj;
uint32 size;
FindObjectInRoom foir;
if (room==(uint)-1)
room = getObjectRoom(img);
findObjectInRoom(&foir, foCodeHeader | foImageHeader | foCheckAlreadyLoaded, img, room);
setCursorHotspot2(
READ_LE_UINT16(&foir.imhd->hotspot[0].x),
READ_LE_UINT16(&foir.imhd->hotspot[0].y));
#if !defined(FULL_THROTTLE)
w = READ_LE_UINT16(&foir.cdhd->v6.w)>>3;
h = READ_LE_UINT16(&foir.cdhd->v6.h)>>3;
#else
w = READ_LE_UINT16(&foir.imhd->width)>>3;
h = READ_LE_UINT16(&foir.imhd->height)>>3;
#endif
dataptr = findResource(IMxx_tags[imgindex],foir.obim);
if (dataptr==NULL)
error("setCursorImg: No such image");
size = READ_BE_UINT32_UNALIGNED(dataptr+4);
if (size > sizeof(_grabbedCursor))
error("setCursorImg: Cursor image too large");
if ((bomp = findResource(MKID('BOMP'), dataptr)) != NULL)
useBompCursor(bomp, w, h);
else
useIm01Cursor(dataptr, w, h);
}
void Scumm::nukeFlObjects(int min, int max) {
ObjectData *od;
int i;
warning("nukeFlObjects(%d,%d)", min, max);
for (i=_numObjectsInRoom,od=_objs; --i>=0; od++)
if (od->fl_object_index && od->obj_nr>=min && od->obj_nr<=max) {
nukeResource(rtFlObject, od->fl_object_index);
od->obj_nr = 0;
od->fl_object_index = 0;
}
}
void Scumm::enqueueObject(int a, int b, int c, int d, int e, int f, int g, int h, int mode) {
EnqueuedObject *eo;
ObjectData *od;
if (_enqueuePos==sizeof(_enqueuedObjects)/sizeof(_enqueuedObjects[0]))
error("enqueueObject: overflow");
eo = &_enqueuedObjects[_enqueuePos++];
eo->a = a;
eo->b = _enqueue_b;
eo->c = _enqueue_c;
eo->d = _enqueue_d;
eo->e = _enqueue_e;
eo->x = b;
eo->y = c;
if (d==0) {
od = &_objs[getObjectIndex(a)];
eo->width = od->width;
} else {
eo->width = d;
}
if (e==0) {
od = &_objs[getObjectIndex(a)];
eo->height = od->height;
} else {
eo->height = e;
}
eo->j = f;
eo->k = g;
eo->l = h;
}
void Scumm::drawEnqueuedObjects() {
EnqueuedObject *eo;
int i;
eo = _enqueuedObjects;
for(i=0; i < _enqueuePos; i++,eo++) {
drawEnqueuedObject(eo);
}
}
void Scumm::drawEnqueuedObject(EnqueuedObject *eo) {
VirtScreen *vs;
byte *roomptr,*bomp;
byte *ptr;
int index;
ObjectData *od;
int width,height;
byte *outptr;
int x,y;
byte *dataptr;
BompDrawData bdd;
vs = &virtscr[0];
_lastXstart = vs->xstart;
if (eo->l==0) {
roomptr = getResourceAddress(1, _roomResource);
index = getObjectIndex(eo->a);
assert(index != -1);
ptr = roomptr + _objs[index].offs_obim_to_room;
} else if (eo->a!=0) {
od = &_objs[getObjectIndex(eo->a)];
ptr = getResourceAddress(rtFlObject, od->fl_object_index);
assert(ptr);
ptr = findResource(MKID('OBIM'), ptr);
} else {
warning("drawEnqueuedObject: invalid");
return;
}
assert(ptr);
ptr = findResource(MKID('IM01'), ptr);
assert(ptr);
bomp = findResourceData(MKID('BOMP'), ptr);
bdd.srcwidth = READ_LE_UINT16(&((BompHeader*)bomp)->width);
bdd.srcheight = READ_LE_UINT16(&((BompHeader*)bomp)->height);
bdd.out = getResourceAddress(rtBuffer, vs->number+1) + vs->xstart;
bdd.outwidth = 320;
bdd.outheight = vs->height;
bdd.dataptr = bomp + 18;
bdd.x = eo->x;
bdd.y = eo->y;
bdd.scale_x = eo->j;
bdd.scale_y = eo->k;
updateDirtyRect(vs->number, bdd.x, bdd.x+bdd.srcwidth, bdd.y, bdd.y+bdd.srcheight, 0);
if (eo->a) {
drawBomp(&bdd);
}
}
void Scumm::removeEnqueuedObjects() {
EnqueuedObject *eo;
int i;
eo = _enqueuedObjects;
for(i=0; i < _enqueuePos; i++,eo++) {
removeEnqueuedObject(eo);
}
clearEnqueue();
}
void Scumm::removeEnqueuedObject(EnqueuedObject *eo) {
restoreBG(eo->x, eo->y, eo->x + eo->width, eo->y + eo->height);
}
int Scumm::findFlObjectSlot() {
int i;
for(i=1; i<_maxFLObject; i++) {
if (_baseFLObject[i] == NULL)
return i;
}
error("findFlObjectSlot: Out of FLObject slots");
}
void Scumm::loadFlObject(uint object, uint room) {
FindObjectInRoom foir;
int slot;
ObjectData *od;
byte *flob,*roomptr;
uint32 obcd_size, obim_size, flob_size;
/* Don't load an already loaded object */
if (whereIsObject(object) != WIO_NOT_FOUND)
return;
/* Locate the object in the room resource */
findObjectInRoom(&foir, foImageHeader | foCodeHeader, object, room);
/* Add an entry for the new floating object in the local object table */
if (++_numObjectsInRoom > _numLocalObjects)
error("loadFlObject: Local Object Table overflow");
od = &_objs[_numObjectsInRoom];
/* Setup sizes */
obcd_size = READ_BE_UINT32_UNALIGNED(foir.obcd + 4);
od->offs_obcd_to_room = 8;
od->offs_obim_to_room = obcd_size + 8;
obim_size = READ_BE_UINT32_UNALIGNED(foir.obim + 4);
flob_size = obcd_size + obim_size + 8;
/* Allocate slot & memory for floating object */
slot = findFlObjectSlot();
createResource(rtFlObject, slot, flob_size);
/* Copy object code + object image to floating object */
roomptr = getResourceAddress(rtRoom, room);
flob = getResourceAddress(rtFlObject, slot);
((uint32*)flob)[0] = MKID('FLOB');
((uint32*)flob)[1] = TO_BE_32(flob_size);
memcpy(flob + 8, roomptr - foir.roomptr + foir.obcd, obcd_size);
memcpy(flob + 8 + obcd_size, roomptr - foir.roomptr + foir.obim, obim_size);
/* Setup local object flags */
setupRoomObject(od, flob);
od->fl_object_index = slot;
}