scummvm/object.cpp
Ludvig Strigeus 38e2a886ce very simple full throttle support, use the FULL_THROTTLE define. (will fix later)
modified some actor parts to work better with full throttle (most likely new bugs because of that).
directions are now stored as angles instead of left/right/up/down
implemented loadFlObject (flobjects are currently saved in the savestate, will fix that also)

svn-id: r3505
2001-11-26 19:57:57 +00:00

1032 lines
24 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 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(_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_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*)findResource(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 = od->walk_x;
y = od->walk_y;
}
// 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::drawRoomObjects(int arg) {
int i;
ObjectData *od;
byte a;
for(i=1; i<=_numObjectsInRoom; i++) {
od = &_objs[i];
if (!od->obj_nr || !od->state || od->fl_object_index)
continue;
do {
a = od->parentstate;
if (!od->parent) {
drawObject(i, arg);
break;
}
od = &_objs[od->parent];
} while (od->state==a);
}
}
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;
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;
}
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 (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*)findResource(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*)findResource(MKID('CDHD'), ptr, 0);
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*)findResource(MKID('IMHD'), ptr, 0);
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::setupRoomObject(ObjectData *od, byte *room) {
byte *obcd;
CodeHeader *cdhd;
ImageHeader *imhd;
cdhd = (CodeHeader*)findResource(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<<4;
} else {
od->parentstate = (cdhd->v6.flags&0xF)<<OF_STATE_SHL;
}
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<<4;
} else {
od->parentstate = (cdhd->v5.flags&0xF)<<OF_STATE_SHL;
}
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*)findResource(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"));
objptr = getObjectAddress(obj);
if (objptr==NULL)
return (byte*)" ";
return findResource(MKID('OBNA'), objptr) + 8;
}
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::getObjectAddress(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) + 64;
size = READ_BE_UINT32_UNALIGNED(ptr+4);
slot = getInventorySlot();
_inventory[slot] = obj;
createResource(rtInventory, slot, size);
ptr = getResourceAddress(rtFlObject, _objs[i].fl_object_index) + 64;
memcpy(getResourceAddress(rtInventory, slot), ptr, size);
} else {
findObjectInRoom(&foir, foCodeHeader, obj, room);
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 = getObjectAddress(id);
assert((byte*)obcdptr > (byte*)256);
fo->obim = obimptr = obcdptr + READ_BE_UINT32(&((ImageHeader*)obcdptr)->size);
fo->cdhd = (CodeHeader*)findResource(MKID('CDHD'), obcdptr);
fo->imhd = (ImageHeader*)findResource(MKID('IMHD'), obimptr);
return;
}
fo->roomptr = roomptr = getResourceAddress(rtRoom, room);
roomhdr = (RoomHeader*)findResource(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;;) {
obcdptr = findResource(MKID('OBCD'), searchptr);
if(obcdptr==NULL)
error("findObjectInRoom: Not enough code blocks in room %d", room);
cdhd = (CodeHeader*)findResource(MKID('CDHD'), obcdptr, 0);
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;;) {
obimptr = findResource(MKID('OBIM'), searchptr);
if (obimptr==NULL)
error("findObjectInRoom: Not enough image blocks in room %d", room);
imhd = (ImageHeader*)findResource(MKID('IMHD'), obimptr, 0);
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) {
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) {
return derefActorSafe(obj,"getObjY")->y;
} else {
if (whereIsObject(obj)==WIO_NOT_FOUND)
return -1;
getObjectOrActorXY(obj);
return _yPos;
}
}
int Scumm::getObjDir(int obj) {
if (obj < NUM_ACTORS) {
return newDirToOldDir(derefActorSafe(obj,"getObjDir")->facing);
} else {
getObjectXYPos(obj);
return _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(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) {
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;
vs = &virtscr[0];
_lastXstart = vs->xstart;
if (eo->l==0) {
roomptr = getResourceAddress(1, _roomResource);
index = getObjectIndex(eo->a);
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);
ptr = findResource(MKID('OBIM'), ptr);
} else {
warning("drawEnqueuedObject: invalid");
return;
}
ptr = findResource(MKID('IM01'), ptr);
bomp = findResource(MKID('BOMP'), ptr);
width = READ_LE_UINT16(&((BompHeader*)bomp)->width);
height = READ_LE_UINT16(&((BompHeader*)bomp)->height);
outptr = getResourceAddress(rtBuffer, vs->number+1) + vs->xstart;
x = eo->x;
y = eo->y;
if (eo->a) {
dataptr = bomp + 18;
}
// debug(1, "drawEnqueuedObject(%d,%d,%d,%d,%d, %d,%d,%d,%d,%d,%d,%d)",
// eo->x, eo->y, eo->width, eo->height, eo->a, eo->b, eo->c, eo->d, eo->e, eo->j, eo->k, eo->l);
updateDirtyRect(vs->number, x, x+width,y,y+height,0);
}
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;
if (room==(uint)-1)
room = getObjectRoom(object);
/* 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(foir.obcd + 4);
od->offs_obcd_to_room = 8;
od->offs_obim_to_room = obcd_size + 8;
obim_size = READ_BE_UINT32(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;
}