2007-05-30 21:56:52 +00:00
|
|
|
/* 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.
|
2001-10-09 14:30:12 +00:00
|
|
|
*
|
2021-12-26 18:47:58 +01:00
|
|
|
* 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 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
2014-02-18 02:34:24 +01:00
|
|
|
*
|
2001-10-09 14:30:12 +00:00
|
|
|
* 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.
|
2014-02-18 02:34:24 +01:00
|
|
|
*
|
2001-10-09 14:30:12 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
2021-12-26 18:47:58 +01:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2001-10-09 14:30:12 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2003-10-03 18:33:57 +00:00
|
|
|
#include "scumm/actor.h"
|
|
|
|
#include "scumm/bomp.h"
|
2006-02-15 00:57:50 +00:00
|
|
|
#include "scumm/he/intern_he.h"
|
2003-10-03 18:33:57 +00:00
|
|
|
#include "scumm/object.h"
|
|
|
|
#include "scumm/resource.h"
|
2009-03-20 16:33:58 +00:00
|
|
|
#include "scumm/scumm_v0.h"
|
|
|
|
#include "scumm/scumm_v8.h"
|
2003-10-03 18:33:57 +00:00
|
|
|
#include "scumm/usage_bits.h"
|
2005-04-10 12:59:17 +00:00
|
|
|
#include "scumm/util.h"
|
2003-10-03 18:33:57 +00:00
|
|
|
|
|
|
|
namespace Scumm {
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2006-10-18 14:21:44 +00:00
|
|
|
void ScummEngine::addObjectToInventory(uint obj, uint room) {
|
|
|
|
int idx, slot;
|
|
|
|
uint32 size;
|
|
|
|
const byte *ptr;
|
|
|
|
byte *dst;
|
|
|
|
FindObjectInRoom foir;
|
|
|
|
|
|
|
|
debug(1, "Adding object %d from room %d into inventory", obj, room);
|
|
|
|
|
|
|
|
if (whereIsObject(obj) == WIO_FLOBJECT) {
|
|
|
|
idx = getObjectIndex(obj);
|
|
|
|
assert(idx >= 0);
|
|
|
|
ptr = getResourceAddress(rtFlObject, _objs[idx].fl_object_index) + 8;
|
2018-05-17 12:40:02 +02:00
|
|
|
assert(ptr);
|
2006-10-18 14:21:44 +00:00
|
|
|
size = READ_BE_UINT32(ptr + 4);
|
|
|
|
} else {
|
|
|
|
findObjectInRoom(&foir, foCodeHeader, obj, room);
|
|
|
|
if (_game.features & GF_OLD_BUNDLE)
|
|
|
|
size = READ_LE_UINT16(foir.obcd);
|
|
|
|
else if (_game.features & GF_SMALL_HEADER)
|
|
|
|
size = READ_LE_UINT32(foir.obcd);
|
|
|
|
else
|
|
|
|
size = READ_BE_UINT32(foir.obcd + 4);
|
|
|
|
ptr = foir.obcd;
|
|
|
|
}
|
|
|
|
|
|
|
|
slot = getInventorySlot();
|
|
|
|
_inventory[slot] = obj;
|
|
|
|
dst = _res->createResource(rtInventory, slot, size);
|
|
|
|
assert(dst);
|
|
|
|
memcpy(dst, ptr, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ScummEngine::getInventorySlot() {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < _numInventory; i++) {
|
|
|
|
if (_inventory[i] == 0)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
error("Inventory full, %d max items", _numInventory);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ScummEngine::findInventory(int owner, int idx) {
|
|
|
|
int count = 1, i, obj;
|
|
|
|
for (i = 0; i < _numInventory; i++) {
|
|
|
|
obj = _inventory[i];
|
|
|
|
if (obj && getOwner(obj) == owner && count++ == idx)
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ScummEngine::getInventoryCount(int owner) {
|
|
|
|
int i, obj;
|
|
|
|
int count = 0;
|
|
|
|
for (i = 0; i < _numInventory; i++) {
|
|
|
|
obj = _inventory[i];
|
|
|
|
if (obj && getOwner(obj) == owner)
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScummEngine::setOwnerOf(int obj, int owner) {
|
|
|
|
ScriptSlot *ss;
|
|
|
|
|
|
|
|
// In Sam & Max this is necessary, or you won't get your stuff back
|
|
|
|
// from the Lost and Found tent after riding the Cone of Tragedy. But
|
2021-06-07 17:44:05 -06:00
|
|
|
// it probably applies to all V6+ games. See bugs #52 and #1507.
|
2011-05-25 10:31:37 -04:00
|
|
|
// FT disassembly is checked, behavior is correct. [sev]
|
2006-10-18 14:21:44 +00:00
|
|
|
|
|
|
|
int arg = (_game.version >= 6) ? obj : 0;
|
|
|
|
|
2021-02-28 01:28:23 -08:00
|
|
|
// WORKAROUND for bug #3657: Game crash when finishing Indy3 demo.
|
2008-09-23 11:43:57 +00:00
|
|
|
// Script 94 tries to empty the inventory but does so in a bogus way.
|
|
|
|
// This causes it to try to remove object 0 from the inventory.
|
|
|
|
if (_game.id == GID_PASS && obj == 0 && vm.slot[_currentScript].number == 94)
|
|
|
|
return;
|
2016-08-03 21:04:58 +02:00
|
|
|
|
|
|
|
// WORKAROUND for bug #6802: assert() was triggered in freddi2.
|
2020-09-26 18:24:45 +02:00
|
|
|
// Bug is in room 39. Problem is script 10, in the localvar2==78 case;
|
2016-08-03 21:04:58 +02:00
|
|
|
// this only sets the obj id if var198 is non-zero, but in the asserting
|
|
|
|
// case, it is obj 0. That means two setOwnerOf calls are made with obj 0.
|
|
|
|
// The correct setOwnerOf calls are made afterwards, so just ignoring this
|
|
|
|
// seems to work just fine.
|
|
|
|
if (_game.id == GID_HEGAME && obj == 0 && _currentRoom == 39 && vm.slot[_currentScript].number == 10)
|
|
|
|
return;
|
|
|
|
|
2008-09-23 11:43:57 +00:00
|
|
|
assert(obj > 0);
|
|
|
|
|
2006-10-18 14:21:44 +00:00
|
|
|
if (owner == 0) {
|
|
|
|
clearOwnerOf(obj);
|
2007-09-19 08:40:12 +00:00
|
|
|
|
2021-02-28 01:28:23 -08:00
|
|
|
// FIXME: See bug #2771 and many others. Essentially, the following
|
2006-10-18 14:21:44 +00:00
|
|
|
// code, while matching disasm of various versions of the SCUMM engine,
|
|
|
|
// is total bullocks, and leads to odd crashes due to out-of-bounds
|
|
|
|
// array (read) access. Three "famous" crashes were caused by this:
|
|
|
|
// Monkey Island 1: Using meat with flower
|
|
|
|
// FOA: Using ribcage with another item
|
|
|
|
// DOTT: Using stamp with contract
|
|
|
|
//
|
|
|
|
// The bad code:
|
|
|
|
// if (ss->where == WIO_INVENTORY && _inventory[ss->number] == obj) {
|
|
|
|
// That check makes no sense at all: _inventory only contains 80 items,
|
2007-09-19 08:40:12 +00:00
|
|
|
// which are in the order the player picked up items. We can only
|
2006-10-18 14:21:44 +00:00
|
|
|
// guess that the SCUMM coders meant to write
|
|
|
|
// if (ss->where == WIO_INVENTORY && ss->number == obj) {
|
|
|
|
// which would ensure that an object script that nukes itself gets
|
|
|
|
// stopped. Alas, we can't just make that change, since it could
|
|
|
|
// lead to new regressions.
|
|
|
|
// Another fix would be to completely remove this check, which should
|
|
|
|
// not cause much problems, since it'll only succeed by pure chance.
|
2007-09-19 08:40:12 +00:00
|
|
|
//
|
2006-10-18 14:21:44 +00:00
|
|
|
// For now we follow a more defensive route: We perform the check
|
|
|
|
// if ss->number is small enough.
|
2007-09-19 08:40:12 +00:00
|
|
|
|
2006-10-18 14:21:44 +00:00
|
|
|
ss = &vm.slot[_currentScript];
|
|
|
|
if (ss->where == WIO_INVENTORY) {
|
|
|
|
if (ss->number < _numInventory && _inventory[ss->number] == obj) {
|
2008-12-09 19:53:01 +00:00
|
|
|
error("Odd setOwnerOf case #1: Please report to Fingolfin where you encountered this");
|
2006-10-18 14:21:44 +00:00
|
|
|
putOwner(obj, 0);
|
|
|
|
runInventoryScript(arg);
|
|
|
|
stopObjectCode();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (ss->number == obj)
|
2008-12-09 19:53:01 +00:00
|
|
|
error("Odd setOwnerOf case #2: Please report to Fingolfin where you encountered this");
|
2006-10-18 14:21:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
putOwner(obj, owner);
|
|
|
|
runInventoryScript(arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScummEngine::clearOwnerOf(int obj) {
|
2007-09-10 13:16:06 +00:00
|
|
|
int i;
|
2006-10-18 14:21:44 +00:00
|
|
|
|
2007-09-10 13:16:06 +00:00
|
|
|
// Stop the associated object script code (else crashes might occurs)
|
2006-10-18 14:21:44 +00:00
|
|
|
stopObjectScript(obj);
|
|
|
|
|
2022-07-29 15:28:41 +02:00
|
|
|
// If the object is "owned" by the current room, we scan the
|
2007-09-10 13:16:06 +00:00
|
|
|
// object list and (only if it's a floating object) nuke it.
|
2006-10-18 14:21:44 +00:00
|
|
|
if (getOwner(obj) == OF_OWNER_ROOM) {
|
|
|
|
for (i = 0; i < _numLocalObjects; i++) {
|
2006-10-19 00:06:59 +00:00
|
|
|
if (_objs[i].obj_nr == obj && _objs[i].fl_object_index) {
|
|
|
|
// Removing an flObject from a room means we can nuke it
|
2006-10-18 14:21:44 +00:00
|
|
|
_res->nukeResource(rtFlObject, _objs[i].fl_object_index);
|
|
|
|
_objs[i].obj_nr = 0;
|
|
|
|
_objs[i].fl_object_index = 0;
|
|
|
|
}
|
|
|
|
}
|
2007-09-10 13:16:06 +00:00
|
|
|
} else {
|
2007-09-19 08:40:12 +00:00
|
|
|
|
2007-09-10 13:16:06 +00:00
|
|
|
// Alternatively, scan the inventory to see if the object is in there...
|
|
|
|
for (i = 0; i < _numInventory; i++) {
|
|
|
|
if (_inventory[i] == obj) {
|
2012-01-07 16:08:55 +01:00
|
|
|
assert(WIO_INVENTORY == whereIsObject(obj));
|
2009-07-25 06:27:41 +00:00
|
|
|
|
2007-09-10 13:16:06 +00:00
|
|
|
// Found the object! Nuke it from the inventory.
|
2006-10-18 14:21:44 +00:00
|
|
|
_res->nukeResource(rtInventory, i);
|
|
|
|
_inventory[i] = 0;
|
2007-09-19 08:40:12 +00:00
|
|
|
|
2007-09-10 13:16:06 +00:00
|
|
|
// Now fill up the gap removing the object from the inventory created.
|
2008-03-19 10:17:29 +00:00
|
|
|
for (i = 0; i < _numInventory - 1; i++) {
|
2007-09-10 13:16:06 +00:00
|
|
|
if (!_inventory[i] && _inventory[i+1]) {
|
|
|
|
_inventory[i] = _inventory[i+1];
|
|
|
|
_inventory[i+1] = 0;
|
2011-05-11 18:06:30 +02:00
|
|
|
// FIXME FIXME FIXME: This is incomplete, as we do not touch flags, status... BUG
|
2011-05-13 14:48:01 +02:00
|
|
|
_res->_types[rtInventory][i]._address = _res->_types[rtInventory][i + 1]._address;
|
|
|
|
_res->_types[rtInventory][i]._size = _res->_types[rtInventory][i + 1]._size;
|
2021-11-13 23:40:38 +02:00
|
|
|
_res->_types[rtInventory][i + 1]._address = nullptr;
|
2011-05-13 14:48:01 +02:00
|
|
|
_res->_types[rtInventory][i + 1]._size = 0;
|
2007-09-10 13:16:06 +00:00
|
|
|
}
|
2006-10-18 14:21:44 +00:00
|
|
|
}
|
2007-09-10 13:16:06 +00:00
|
|
|
break;
|
2006-10-18 14:21:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
bool ScummEngine::getClass(int obj, int cls) const {
|
2012-01-16 22:32:46 +01:00
|
|
|
if (_game.version == 0)
|
|
|
|
return false;
|
|
|
|
|
2006-09-16 13:38:43 +00:00
|
|
|
assertRange(0, obj, _numGlobalObjects - 1, "object");
|
2002-04-03 16:20:17 +00:00
|
|
|
cls &= 0x7F;
|
2006-09-16 13:38:43 +00:00
|
|
|
assertRange(1, cls, 32, "class");
|
2002-04-03 16:20:17 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.features & GF_SMALL_HEADER) {
|
2003-05-20 20:42:28 +00:00
|
|
|
// Translate the new (V5) object classes to the old classes
|
|
|
|
// (for those which differ).
|
|
|
|
switch (cls) {
|
2003-09-24 06:33:59 +00:00
|
|
|
case kObjectClassUntouchable:
|
|
|
|
cls = 24;
|
|
|
|
break;
|
|
|
|
case kObjectClassPlayer:
|
|
|
|
cls = 23;
|
|
|
|
break;
|
|
|
|
case kObjectClassXFlip:
|
|
|
|
cls = 19;
|
|
|
|
break;
|
|
|
|
case kObjectClassYFlip:
|
|
|
|
cls = 18;
|
|
|
|
break;
|
2019-12-23 11:56:16 +00:00
|
|
|
default:
|
|
|
|
break;
|
2003-05-20 20:42:28 +00:00
|
|
|
}
|
2002-04-03 15:45:32 +00:00
|
|
|
}
|
2003-05-20 20:42:28 +00:00
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
return (_classData[obj] & (1 << (cls - 1))) != 0;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
void ScummEngine::putClass(int obj, int cls, bool set) {
|
2012-01-16 22:32:46 +01:00
|
|
|
if (_game.version == 0)
|
|
|
|
return;
|
|
|
|
|
2006-09-16 13:38:43 +00:00
|
|
|
assertRange(0, obj, _numGlobalObjects - 1, "object");
|
2001-10-09 14:30:12 +00:00
|
|
|
cls &= 0x7F;
|
2006-09-16 13:38:43 +00:00
|
|
|
assertRange(1, cls, 32, "class");
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.features & GF_SMALL_HEADER) {
|
2003-05-20 20:42:28 +00:00
|
|
|
// Translate the new (V5) object classes to the old classes
|
|
|
|
// (for those which differ).
|
|
|
|
switch (cls) {
|
2003-09-24 06:33:59 +00:00
|
|
|
case kObjectClassUntouchable:
|
|
|
|
cls = 24;
|
|
|
|
break;
|
|
|
|
case kObjectClassPlayer:
|
|
|
|
cls = 23;
|
|
|
|
break;
|
|
|
|
case kObjectClassXFlip:
|
|
|
|
cls = 19;
|
|
|
|
break;
|
|
|
|
case kObjectClassYFlip:
|
|
|
|
cls = 18;
|
|
|
|
break;
|
2019-12-23 11:56:16 +00:00
|
|
|
default:
|
|
|
|
break;
|
2003-05-20 20:42:28 +00:00
|
|
|
}
|
2002-04-03 16:20:17 +00:00
|
|
|
}
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2002-04-11 15:22:02 +00:00
|
|
|
if (set)
|
2002-04-11 17:19:16 +00:00
|
|
|
_classData[obj] |= (1 << (cls - 1));
|
2002-04-11 15:22:02 +00:00
|
|
|
else
|
2002-04-11 17:19:16 +00:00
|
|
|
_classData[obj] &= ~(1 << (cls - 1));
|
2002-07-26 16:13:04 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version <= 4 && obj >= 1 && obj < _numActors) {
|
2006-12-25 15:03:36 +00:00
|
|
|
_actors[obj]->classChanged(cls, set);
|
2002-07-26 16:13:04 +00:00
|
|
|
}
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::getOwner(int obj) const {
|
2006-09-16 13:38:43 +00:00
|
|
|
assertRange(0, obj, _numGlobalObjects - 1, "object");
|
2001-11-26 19:57:57 +00:00
|
|
|
return _objectOwnerTable[obj];
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
void ScummEngine::putOwner(int obj, int owner) {
|
2006-09-16 13:38:43 +00:00
|
|
|
assertRange(0, obj, _numGlobalObjects - 1, "object");
|
|
|
|
assertRange(0, owner, 0xFF, "owner");
|
2002-07-02 21:29:24 +00:00
|
|
|
_objectOwnerTable[obj] = owner;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::getState(int obj) {
|
2006-09-16 13:38:43 +00:00
|
|
|
assertRange(0, obj, _numGlobalObjects - 1, "object");
|
2003-06-16 14:45:23 +00:00
|
|
|
|
2003-12-11 06:08:43 +00:00
|
|
|
if (!_copyProtection) {
|
|
|
|
// I knew LucasArts sold cracked copies of the original Maniac Mansion,
|
|
|
|
// at least as part of Day of the Tentacle. Apparently they also sold
|
|
|
|
// cracked versions of the enhanced version. At least in Germany.
|
|
|
|
//
|
|
|
|
// This will keep the security door open at all times. I can only
|
|
|
|
// assume that 182 and 193 each correspond to one particular side of
|
2006-10-18 15:08:43 +00:00
|
|
|
// it. Fortunately this does not prevent frustrated players from
|
2003-12-11 06:08:43 +00:00
|
|
|
// blowing up the mansion, should they feel the urge to.
|
|
|
|
|
2022-05-21 13:43:58 +02:00
|
|
|
if (_game.id == GID_MANIAC && _game.version != 0 && _game.platform != Common::kPlatformNES && (obj == 182 || obj == 193))
|
2006-10-29 14:45:31 +00:00
|
|
|
_objectStateTable[obj] |= kObjectState_08;
|
2003-12-11 06:08:43 +00:00
|
|
|
}
|
2003-06-16 14:45:23 +00:00
|
|
|
|
2002-07-02 21:29:24 +00:00
|
|
|
return _objectStateTable[obj];
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
void ScummEngine::putState(int obj, int state) {
|
2006-09-16 13:38:43 +00:00
|
|
|
assertRange(0, obj, _numGlobalObjects - 1, "object");
|
|
|
|
assertRange(0, state, 0xFF, "state");
|
2002-07-02 21:29:24 +00:00
|
|
|
_objectStateTable[obj] = state;
|
2001-11-26 19:57:57 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::getObjectRoom(int obj) const {
|
2006-09-16 13:38:43 +00:00
|
|
|
assertRange(0, obj, _numGlobalObjects - 1, "object");
|
2001-11-26 19:57:57 +00:00
|
|
|
return _objectRoomTable[obj];
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::getObjectIndex(int object) const {
|
2001-10-09 14:30:12 +00:00
|
|
|
int i;
|
|
|
|
|
2012-01-16 22:32:46 +01:00
|
|
|
if (object < 1)
|
2003-01-12 07:30:17 +00:00
|
|
|
return -1;
|
|
|
|
|
2003-05-22 15:27:44 +00:00
|
|
|
for (i = (_numLocalObjects-1); i > 0; i--) {
|
2012-01-16 22:32:46 +01:00
|
|
|
if (_objs[i].obj_nr == object)
|
2003-05-22 15:27:44 +00:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::whereIsObject(int object) const {
|
2001-10-09 14:30:12 +00:00
|
|
|
int i;
|
|
|
|
|
2012-02-04 18:34:08 +01:00
|
|
|
// Note: in MM v0 bg objects are greater _numGlobalObjects
|
2012-01-07 16:08:55 +01:00
|
|
|
if (_game.version != 0 && object >= _numGlobalObjects)
|
2001-11-12 20:50:36 +00:00
|
|
|
return WIO_NOT_FOUND;
|
2001-11-06 21:29:23 +00:00
|
|
|
|
2003-01-12 07:30:17 +00:00
|
|
|
if (object < 1)
|
|
|
|
return WIO_NOT_FOUND;
|
|
|
|
|
2012-01-07 16:08:55 +01:00
|
|
|
if ((_game.version != 0 || OBJECT_V0_TYPE(object) == 0) &&
|
2012-09-26 04:17:31 +02:00
|
|
|
_objectOwnerTable[object] != OF_OWNER_ROOM)
|
2012-01-07 16:08:55 +01:00
|
|
|
{
|
2003-12-26 23:11:35 +00:00
|
|
|
for (i = 0; i < _numInventory; i++)
|
2001-10-09 14:30:12 +00:00
|
|
|
if (_inventory[i] == object)
|
2001-11-12 20:50:36 +00:00
|
|
|
return WIO_INVENTORY;
|
|
|
|
return WIO_NOT_FOUND;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2012-01-07 16:08:55 +01:00
|
|
|
for (i = (_numLocalObjects-1); i > 0; i--) {
|
2012-01-16 22:32:46 +01:00
|
|
|
if (_objs[i].obj_nr == object) {
|
2001-10-16 10:01:48 +00:00
|
|
|
if (_objs[i].fl_object_index)
|
2001-11-12 20:50:36 +00:00
|
|
|
return WIO_FLOBJECT;
|
|
|
|
return WIO_ROOM;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2012-01-07 16:08:55 +01:00
|
|
|
}
|
2003-01-11 18:52:19 +00:00
|
|
|
|
2001-11-12 20:50:36 +00:00
|
|
|
return WIO_NOT_FOUND;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2022-07-27 15:03:36 +02:00
|
|
|
int ScummEngine::getObjectOrActorWidth(int object, int &width) {
|
|
|
|
Actor *act;
|
|
|
|
|
|
|
|
if (objIsActor(object)) {
|
|
|
|
act = derefActorSafe(objToActor(object), "getObjectOrActorWidth");
|
|
|
|
if (act && act->isInCurrentRoom()) {
|
|
|
|
width = act->_width;
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (whereIsObject(object)) {
|
|
|
|
case WIO_NOT_FOUND:
|
|
|
|
return -1;
|
|
|
|
case WIO_INVENTORY:
|
|
|
|
if (objIsActor(_objectOwnerTable[object])) {
|
|
|
|
act = derefActor(_objectOwnerTable[object], "getObjectOrActorWidth(2)");
|
|
|
|
if (act && act->isInCurrentRoom()) {
|
|
|
|
width = act->_width;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
getObjectWidth(object, width);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::getObjectOrActorXY(int object, int &x, int &y) {
|
2006-11-19 00:39:48 +00:00
|
|
|
Actor *act;
|
|
|
|
|
2012-01-22 22:58:10 +01:00
|
|
|
if (objIsActor(object)) {
|
|
|
|
act = derefActorSafe(objToActor(object), "getObjectOrActorXY");
|
2006-11-19 00:39:48 +00:00
|
|
|
if (act && act->isInCurrentRoom()) {
|
2007-02-04 01:24:43 +00:00
|
|
|
x = act->getRealPos().x;
|
|
|
|
y = act->getRealPos().y;
|
2006-11-19 00:39:48 +00:00
|
|
|
return 0;
|
|
|
|
} else
|
2003-07-28 00:04:20 +00:00
|
|
|
return -1;
|
2002-07-30 11:43:30 +00:00
|
|
|
}
|
2002-04-11 17:19:16 +00:00
|
|
|
|
|
|
|
switch (whereIsObject(object)) {
|
2001-11-12 20:50:36 +00:00
|
|
|
case WIO_NOT_FOUND:
|
2001-10-09 14:30:12 +00:00
|
|
|
return -1;
|
2002-04-11 17:19:16 +00:00
|
|
|
case WIO_INVENTORY:
|
2012-01-22 22:58:10 +01:00
|
|
|
if (objIsActor(_objectOwnerTable[object])) {
|
2006-11-19 00:39:48 +00:00
|
|
|
act = derefActor(_objectOwnerTable[object], "getObjectOrActorXY(2)");
|
|
|
|
if (act && act->isInCurrentRoom()) {
|
2007-02-04 01:24:43 +00:00
|
|
|
x = act->getRealPos().x;
|
|
|
|
y = act->getRealPos().y;
|
2006-11-19 00:39:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
2019-12-23 11:56:16 +00:00
|
|
|
default:
|
|
|
|
break;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2002-07-16 18:51:27 +00:00
|
|
|
getObjectXYPos(object, x, y);
|
2001-10-09 14:30:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-05-30 20:13:29 +00:00
|
|
|
/**
|
|
|
|
* Return the position of an object.
|
|
|
|
* Returns X, Y and direction in angles
|
2001-11-26 19:57:57 +00:00
|
|
|
*/
|
2022-07-27 15:03:36 +02:00
|
|
|
void ScummEngine::getObjectXYPos(int object, int &x, int &y, int &dir, int &width) {
|
2012-01-07 16:08:55 +01:00
|
|
|
int idx = getObjectIndex(object);
|
2003-07-28 01:09:54 +00:00
|
|
|
assert(idx >= 0);
|
|
|
|
ObjectData &od = _objs[idx];
|
2001-10-16 10:01:48 +00:00
|
|
|
int state;
|
2003-05-28 20:01:47 +00:00
|
|
|
const byte *ptr;
|
|
|
|
const ImageHeader *imhd;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version >= 6) {
|
2003-01-13 15:27:06 +00:00
|
|
|
state = getState(object) - 1;
|
|
|
|
if (state < 0)
|
|
|
|
state = 0;
|
|
|
|
|
2005-06-23 14:10:52 +00:00
|
|
|
ptr = getOBIMFromObjectData(od);
|
2003-05-30 00:40:58 +00:00
|
|
|
if (!ptr) {
|
|
|
|
// FIXME: We used to assert here, but it seems that in the nexus
|
|
|
|
// in The Dig, this can happen, at least with old savegames, and
|
|
|
|
// it's safe to continue...
|
2005-08-14 02:04:26 +00:00
|
|
|
debug(0, "getObjectXYPos: Can't find object %d", object);
|
2003-05-30 00:40:58 +00:00
|
|
|
return;
|
|
|
|
}
|
2011-04-12 16:53:15 +02:00
|
|
|
imhd = (const ImageHeader *)findResourceData(MKTAG('I','M','H','D'), ptr);
|
2003-07-28 00:33:05 +00:00
|
|
|
assert(imhd);
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version == 8) {
|
2004-08-27 23:50:45 +00:00
|
|
|
switch (FROM_LE_32(imhd->v8.version)) {
|
|
|
|
case 800:
|
|
|
|
x = od.x_pos + (int32)READ_LE_UINT32((const byte *)imhd + 8 * state + 0x44);
|
2005-07-30 21:11:48 +00:00
|
|
|
y = od.y_pos + (int32)READ_LE_UINT32((const byte *)imhd + 8 * state + 0x48);
|
2004-08-27 23:50:45 +00:00
|
|
|
break;
|
|
|
|
case 801:
|
|
|
|
x = od.x_pos + (int32)READ_LE_UINT32(&imhd->v8.hotspot[state].x);
|
|
|
|
y = od.y_pos + (int32)READ_LE_UINT32(&imhd->v8.hotspot[state].y);
|
|
|
|
break;
|
|
|
|
default:
|
2009-05-31 10:02:16 +00:00
|
|
|
error("Unsupported image header version %d", FROM_LE_32(imhd->v8.version));
|
2004-08-27 23:50:45 +00:00
|
|
|
}
|
2006-02-20 16:51:30 +00:00
|
|
|
} else if (_game.version == 7) {
|
2003-06-26 01:46:41 +00:00
|
|
|
x = od.x_pos + (int16)READ_LE_UINT16(&imhd->v7.hotspot[state].x);
|
|
|
|
y = od.y_pos + (int16)READ_LE_UINT16(&imhd->v7.hotspot[state].y);
|
2003-01-13 15:27:06 +00:00
|
|
|
} else {
|
2003-06-26 01:46:41 +00:00
|
|
|
x = od.x_pos + (int16)READ_LE_UINT16(&imhd->old.hotspot[state].x);
|
|
|
|
y = od.y_pos + (int16)READ_LE_UINT16(&imhd->old.hotspot[state].y);
|
2002-04-11 17:19:16 +00:00
|
|
|
}
|
2007-02-04 01:24:43 +00:00
|
|
|
} else if (_game.version <= 2) {
|
2012-11-06 14:18:44 +02:00
|
|
|
x = od.walk_x;
|
|
|
|
y = od.walk_y;
|
|
|
|
|
|
|
|
// Adjust x, y when no actor direction is set, but only perform this
|
|
|
|
// adjustment for V0 games (e.g. MM C64), otherwise certain scenes in
|
|
|
|
// newer games are affected as well (e.g. the interior of the Shuttle
|
2021-02-28 01:28:23 -08:00
|
|
|
// Bus scene in Zak V2, where no actor is present). Refer to bug #6034.
|
2012-11-06 14:18:44 +02:00
|
|
|
if (!od.actordir && _game.version == 0) {
|
2012-02-10 22:58:59 +01:00
|
|
|
x = od.x_pos + od.width / 2;
|
|
|
|
y = od.y_pos + od.height / 2;
|
2012-01-08 23:51:13 +01:00
|
|
|
}
|
|
|
|
x = x >> V12_X_SHIFT;
|
|
|
|
y = y >> V12_Y_SHIFT;
|
2002-04-11 17:19:16 +00:00
|
|
|
} else {
|
2003-06-26 01:46:41 +00:00
|
|
|
x = od.walk_x;
|
|
|
|
y = od.walk_y;
|
2002-04-11 17:19:16 +00:00
|
|
|
}
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version == 8)
|
2003-06-26 01:46:41 +00:00
|
|
|
dir = fromSimpleDir(1, od.actordir);
|
2003-02-27 10:42:12 +00:00
|
|
|
else
|
2003-06-26 01:46:41 +00:00
|
|
|
dir = oldDirToNewDir(od.actordir & 3);
|
2001-10-16 10:01:48 +00:00
|
|
|
}
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2009-07-25 06:27:41 +00:00
|
|
|
int ScummEngine::getDist(int x, int y, int x2, int y2) {
|
2003-09-11 23:23:40 +00:00
|
|
|
int a = ABS(y - y2);
|
|
|
|
int b = ABS(x - x2);
|
|
|
|
return MAX(a, b);
|
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::getObjActToObjActDist(int a, int b) {
|
2003-12-06 14:19:34 +00:00
|
|
|
int x, y, x2, y2;
|
2021-11-13 23:40:38 +02:00
|
|
|
Actor *acta = nullptr;
|
|
|
|
Actor *actb = nullptr;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2012-01-22 22:58:10 +01:00
|
|
|
if (objIsActor(a))
|
|
|
|
acta = derefActorSafe(objToActor(a), "getObjActToObjActDist");
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2012-01-22 22:58:10 +01:00
|
|
|
if (objIsActor(b))
|
|
|
|
actb = derefActorSafe(objToActor(b), "getObjActToObjActDist(2)");
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2002-07-07 20:25:23 +00:00
|
|
|
if (acta && actb && acta->getRoom() == actb->getRoom() && acta->getRoom() && !acta->isInCurrentRoom())
|
2002-04-11 17:19:16 +00:00
|
|
|
return 0;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2002-07-16 18:51:27 +00:00
|
|
|
if (getObjectOrActorXY(a, x, y) == -1)
|
2001-10-09 14:30:12 +00:00
|
|
|
return 0xFF;
|
|
|
|
|
2002-07-16 18:51:27 +00:00
|
|
|
if (getObjectOrActorXY(b, x2, y2) == -1)
|
2001-10-09 14:30:12 +00:00
|
|
|
return 0xFF;
|
|
|
|
|
2003-12-06 15:59:17 +00:00
|
|
|
// Perform adjustXYToBeInBox() *only* if the first item is an
|
|
|
|
// actor and the second is an object. This used to not check
|
|
|
|
// whether the second item is a non-actor, which caused bug
|
2021-06-07 17:44:05 -06:00
|
|
|
// #1320).
|
2003-12-06 15:59:17 +00:00
|
|
|
if (acta && !actb) {
|
2003-05-20 19:35:40 +00:00
|
|
|
AdjustBoxResult r = acta->adjustXYToBeInBox(x2, y2);
|
2002-07-16 18:51:27 +00:00
|
|
|
x2 = r.x;
|
|
|
|
y2 = r.y;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-09-19 01:12:05 +00:00
|
|
|
|
2007-02-04 01:24:43 +00:00
|
|
|
// Now compute the distance between the two points
|
2003-12-06 14:19:34 +00:00
|
|
|
return getDist(x, y, x2, y2);
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::findObject(int x, int y) {
|
2002-04-11 17:19:16 +00:00
|
|
|
int i, b;
|
2001-11-26 19:57:57 +00:00
|
|
|
byte a;
|
2006-10-29 14:45:31 +00:00
|
|
|
const int mask = (_game.version <= 2) ? kObjectState_08 : 0xF;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2003-01-12 08:32:44 +00:00
|
|
|
for (i = 1; i < _numLocalObjects; i++) {
|
2003-05-20 20:42:28 +00:00
|
|
|
if ((_objs[i].obj_nr < 1) || getClass(_objs[i].obj_nr, kObjectClassUntouchable))
|
2001-10-09 14:30:12 +00:00
|
|
|
continue;
|
2005-09-14 09:37:17 +00:00
|
|
|
|
2012-01-16 22:32:46 +01:00
|
|
|
if ((_game.version == 0 && OBJECT_V0_TYPE(_objs[i].obj_nr) == kObjectV0TypeFG) ||
|
|
|
|
(_game.version > 0 && _game.version <= 2)) {
|
|
|
|
if (_objs[i].state & kObjectStateUntouchable)
|
2005-09-14 09:37:17 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2001-10-09 14:30:12 +00:00
|
|
|
b = i;
|
|
|
|
do {
|
2001-10-16 10:01:48 +00:00
|
|
|
a = _objs[b].parentstate;
|
|
|
|
b = _objs[b].parent;
|
2002-04-11 17:19:16 +00:00
|
|
|
if (b == 0) {
|
2008-05-06 03:00:26 +00:00
|
|
|
#ifdef ENABLE_HE
|
2007-12-27 11:40:29 +00:00
|
|
|
if (_game.heversion >= 71) {
|
|
|
|
if (((ScummEngine_v71he *)this)->_wiz->polygonHit(_objs[i].obj_nr, x, y))
|
2005-03-28 10:02:22 +00:00
|
|
|
return _objs[i].obj_nr;
|
|
|
|
}
|
2005-05-14 14:06:37 +00:00
|
|
|
#endif
|
2021-08-02 19:40:16 +02:00
|
|
|
if (_game.id == GID_CMI || _game.id == GID_DIG) {
|
|
|
|
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;
|
|
|
|
} else {
|
|
|
|
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;
|
|
|
|
}
|
2001-10-09 14:30:12 +00:00
|
|
|
break;
|
|
|
|
}
|
2003-05-10 22:12:23 +00:00
|
|
|
} while ((_objs[b].state & mask) == a);
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2001-10-09 14:30:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
void ScummEngine::drawRoomObject(int i, int arg) {
|
2001-10-09 14:30:12 +00:00
|
|
|
ObjectData *od;
|
2001-11-26 19:57:57 +00:00
|
|
|
byte a;
|
2006-10-29 14:45:31 +00:00
|
|
|
const int mask = (_game.version <= 2) ? kObjectState_08 : 0xF;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2001-12-04 21:44:41 +00:00
|
|
|
od = &_objs[i];
|
2003-01-12 07:30:17 +00:00
|
|
|
if ((i < 1) || (od->obj_nr < 1) || !od->state)
|
2001-12-04 21:44:41 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
do {
|
|
|
|
a = od->parentstate;
|
|
|
|
if (!od->parent) {
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version <= 6 || od->fl_object_index == 0)
|
2004-02-15 13:06:09 +00:00
|
|
|
drawObject(i, arg);
|
2001-12-04 21:44:41 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
od = &_objs[od->parent];
|
2003-05-10 22:12:23 +00:00
|
|
|
} while ((od->state & mask) == a);
|
2001-12-04 21:44:41 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
void ScummEngine::drawRoomObjects(int arg) {
|
2001-12-04 21:44:41 +00:00
|
|
|
int i;
|
2006-10-29 14:45:31 +00:00
|
|
|
const int mask = (_game.version <= 2) ? kObjectState_08 : 0xF;
|
2001-12-04 21:44:41 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.heversion >= 60) {
|
2005-04-18 07:30:26 +00:00
|
|
|
// In HE games, normal objects are drawn, followed by FlObjects.
|
2005-04-18 07:41:08 +00:00
|
|
|
for (i = (_numLocalObjects-1); i > 0; i--) {
|
2005-04-18 07:30:26 +00:00
|
|
|
if (_objs[i].obj_nr > 0 && (_objs[i].state & mask) && _objs[i].fl_object_index == 0)
|
|
|
|
drawRoomObject(i, arg);
|
|
|
|
}
|
2005-10-13 15:02:21 +00:00
|
|
|
for (i = (_numLocalObjects-1); i > 0; i--) {
|
2005-04-18 07:30:26 +00:00
|
|
|
if (_objs[i].obj_nr > 0 && (_objs[i].state & mask) && _objs[i].fl_object_index != 0)
|
|
|
|
drawRoomObject(i, arg);
|
|
|
|
}
|
2006-02-20 16:51:30 +00:00
|
|
|
} else if (_game.id == GID_SAMNMAX) {
|
2005-04-03 22:10:10 +00:00
|
|
|
// In Sam & Max, objects are drawn in reverse order.
|
2003-01-12 08:32:44 +00:00
|
|
|
for (i = 1; i < _numLocalObjects; i++)
|
2003-01-12 07:30:17 +00:00
|
|
|
if (_objs[i].obj_nr > 0)
|
|
|
|
drawRoomObject(i, arg);
|
2001-12-04 21:44:41 +00:00
|
|
|
} else {
|
2003-01-12 08:37:59 +00:00
|
|
|
for (i = (_numLocalObjects-1); i > 0; i--)
|
2003-05-10 22:12:23 +00:00
|
|
|
if (_objs[i].obj_nr > 0 && (_objs[i].state & mask)) {
|
2003-01-12 07:30:17 +00:00
|
|
|
drawRoomObject(i, arg);
|
2003-05-10 22:12:23 +00:00
|
|
|
}
|
2001-11-26 19:57:57 +00:00
|
|
|
}
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
void ScummEngine::drawObject(int obj, int arg) {
|
2004-08-23 00:17:07 +00:00
|
|
|
if (_skipDrawObject)
|
|
|
|
return;
|
|
|
|
|
2003-06-26 01:46:41 +00:00
|
|
|
ObjectData &od = _objs[obj];
|
2005-03-28 20:18:36 +00:00
|
|
|
int height, width;
|
2003-05-28 20:01:47 +00:00
|
|
|
const byte *ptr;
|
2002-04-11 17:19:16 +00:00
|
|
|
int x, a, numstrip;
|
2001-10-26 17:34:50 +00:00
|
|
|
int tmp;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2004-09-18 22:42:45 +00:00
|
|
|
if (_bgNeedsRedraw)
|
2001-10-09 14:30:12 +00:00
|
|
|
arg = 0;
|
|
|
|
|
2004-01-16 08:23:46 +00:00
|
|
|
if (od.obj_nr == 0)
|
|
|
|
return;
|
|
|
|
|
2006-09-16 13:38:43 +00:00
|
|
|
assertRange(0, od.obj_nr, _numGlobalObjects - 1, "object");
|
2003-01-13 15:27:06 +00:00
|
|
|
|
2005-03-28 20:18:36 +00:00
|
|
|
const int xpos = od.x_pos / 8;
|
|
|
|
const int ypos = od.y_pos;
|
2002-04-24 04:26:09 +00:00
|
|
|
|
2022-04-17 06:40:57 +02:00
|
|
|
// In most cases we want to mask out the last three bits, though it is
|
|
|
|
// possible that this has already been done by resetRoomObject(). In
|
|
|
|
// later versions we need to keep those bits intact. See bug #13419 for
|
|
|
|
// an example of where this is important.
|
|
|
|
|
|
|
|
if (_game.version < 7)
|
|
|
|
od.height &= 0xFFFFFFF8;
|
|
|
|
|
2003-11-16 20:52:57 +00:00
|
|
|
width = od.width / 8;
|
2022-04-17 06:40:57 +02:00
|
|
|
height = od.height;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2004-01-11 21:48:31 +00:00
|
|
|
// Short circuit for objects which aren't visible at all.
|
2002-07-07 20:25:23 +00:00
|
|
|
if (width == 0 || xpos > _screenEndStrip || xpos + width < _screenStartStrip)
|
2001-10-09 14:30:12 +00:00
|
|
|
return;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2009-03-01 03:45:42 +00:00
|
|
|
// For objects without image in Apple II & Commodore 64 versions of Maniac Mansion
|
|
|
|
if (_game.version == 0 && od.OBIMoffset == 0)
|
|
|
|
return;
|
2002-12-31 03:26:02 +00:00
|
|
|
|
2009-03-01 03:45:42 +00:00
|
|
|
ptr = getObjectImage(getOBIMFromObjectData(od), getState(od.obj_nr));
|
2001-10-09 14:30:12 +00:00
|
|
|
if (!ptr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
x = 0xFFFF;
|
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
for (a = numstrip = 0; a < width; a++) {
|
2001-10-26 17:34:50 +00:00
|
|
|
tmp = xpos + a;
|
2005-11-18 00:01:46 +00:00
|
|
|
if (tmp < _screenStartStrip || _screenEndStrip < tmp)
|
2001-10-09 14:30:12 +00:00
|
|
|
continue;
|
2005-11-18 00:01:46 +00:00
|
|
|
if (arg > 0 && _screenStartStrip + arg <= tmp)
|
2001-10-09 14:30:12 +00:00
|
|
|
continue;
|
2005-11-18 00:01:46 +00:00
|
|
|
if (arg < 0 && tmp <= _screenEndStrip + arg)
|
2001-10-09 14:30:12 +00:00
|
|
|
continue;
|
2003-01-14 10:06:56 +00:00
|
|
|
setGfxUsageBit(tmp, USAGE_BIT_DIRTY);
|
2001-10-26 17:34:50 +00:00
|
|
|
if (tmp < x)
|
|
|
|
x = tmp;
|
|
|
|
numstrip++;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
SCUMM: Fix an original tapestry glitch in Indy3 VGA (Trac#3208)
The 256-color versions of Indy3 have a very strange vertical line on the
big tapestry that's in the middle of room 135, in Castle Brunwald.
It looks like an artist made some wrong click when redrawing this object
for the VGA versions, or maybe the compression routine for those images
had some bug. QA was probably rushed for this port, too, since Indy3 has
various oversights related to the VGA conversion. A similar problem was
fixed in commit 6735e3c0f006730831f020e31b3385ee55f58edb.
The tapestry glitch was a bit harder to fix, because the glitched line
hides several pixels with different colors, and because this resource is
in a compressed format. AFAICS, v3 games have no concept of transparent
pixels for background objects, so that simpler solution wouldn't work
either. We could also trim the leftmost OI strip (since the wall in the
background is fine), but I couldn't get this to safely work with the way
unkDecode11() works.
So I have redrawn a fixed OI_0324 with the old BMRP.EXE tool, diffed
the two resources and then added a small mechanism which patches (for
copyright reasons) the impacted bytes from the original resource, as
it is being read. This is a very low-level trick, so various checks
have been added to make sure that we're not corrupting something
(incl. any fan-made modified Indy3), and also in order to make the
workaround a bit easier to follow.
(The most obsessive players will notice that the tapestry still cuts
through a part of the column in the upper-right corner, but I'm only
interested in fixing the obvious problem which was right in the
middle of the room. Sorry if you wished you hadn't seen this.)
2022-09-25 21:13:55 +02:00
|
|
|
byte *patchedBmpPtr = nullptr;
|
|
|
|
// WORKAROUND bug #3208: in all 256-color versions of Indy3, the tapestry
|
|
|
|
// in one of the first rooms of Castle Brunwald has a strange vertical
|
|
|
|
// line at the bottom of its first 'strip' (purple in the DOS version,
|
|
|
|
// blue on the FM-TOWNS). We can't include the whole redrawn resource for
|
|
|
|
// copyright reasons, so we just patch the impacted bytes from a fixed OI
|
|
|
|
// (made with BMRP.EXE).
|
|
|
|
if (_game.id == GID_INDY3 && (_game.features & GF_OLD256) && _currentRoom == 135
|
|
|
|
&& od.obj_nr == 324 && numstrip == od.width / 8 && _enableEnhancements) {
|
|
|
|
// Extra safety: make sure that the OI has the expected length. Indy3
|
|
|
|
// should always be GF_SMALL_HEADER, but that's implicit, so do an
|
|
|
|
// explicit check, since we're doing some low-level byte tricks.
|
|
|
|
const uint32 origOILen = 6184, firstPartLen = 123, droppedPartLen = 3, patchLen = 8;
|
|
|
|
const int nextObjIdx = getObjectIndex(od.obj_nr + 1);
|
|
|
|
if ((_game.features & GF_SMALL_HEADER) && nextObjIdx != -1 &&
|
|
|
|
_objs[nextObjIdx].OBIMoffset - od.OBIMoffset == origOILen && READ_LE_UINT32(ptr) == 6146) {
|
|
|
|
// Copy the original (compressed) OI and patch the faulty content
|
|
|
|
patchedBmpPtr = new byte[origOILen - 8 + patchLen - droppedPartLen];
|
|
|
|
memcpy(patchedBmpPtr, ptr, firstPartLen);
|
|
|
|
memcpy(patchedBmpPtr + firstPartLen, "\x08\xAF\xE0\xC7\x47\xB8\xF1\x11", patchLen);
|
|
|
|
memcpy(patchedBmpPtr + firstPartLen + patchLen, ptr + (firstPartLen + droppedPartLen),
|
|
|
|
origOILen - 8 - (firstPartLen + droppedPartLen));
|
|
|
|
|
|
|
|
// Adjust the offsets for the new OI size
|
|
|
|
WRITE_LE_UINT32(patchedBmpPtr, READ_LE_UINT32(patchedBmpPtr) + (patchLen - droppedPartLen));
|
|
|
|
for (int i = 2; i <= od.width / 8; i++)
|
|
|
|
WRITE_LE_UINT32(patchedBmpPtr + i * 4, READ_LE_UINT32(patchedBmpPtr + i * 4) + (patchLen - droppedPartLen));
|
|
|
|
|
|
|
|
ptr = patchedBmpPtr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
if (numstrip != 0) {
|
2005-03-28 20:18:36 +00:00
|
|
|
byte flags = od.flags | Gdi::dbObjectMode;
|
2004-09-26 08:50:10 +00:00
|
|
|
|
2003-06-06 07:35:19 +00:00
|
|
|
// Sam & Max needs this to fix object-layering problems with
|
|
|
|
// the inventory and conversation icons.
|
2006-02-20 16:51:30 +00:00
|
|
|
if ((_game.id == GID_SAMNMAX && getClass(od.obj_nr, kObjectClassIgnoreBoxes)) ||
|
|
|
|
(_game.id == GID_FT && getClass(od.obj_nr, kObjectClassPlayer)))
|
2002-09-29 15:20:02 +00:00
|
|
|
flags |= Gdi::dbDrawMaskOnAll;
|
2004-09-05 17:39:54 +00:00
|
|
|
|
2008-05-06 03:00:26 +00:00
|
|
|
#ifdef ENABLE_HE
|
2011-04-12 16:53:15 +02:00
|
|
|
if (_game.heversion >= 70 && findResource(MKTAG('S','M','A','P'), ptr) == NULL)
|
2007-09-08 11:15:27 +00:00
|
|
|
_gdi->drawBMAPObject(ptr, &_virtscr[kMainVirtScreen], obj, od.x_pos, od.y_pos, od.width, od.height);
|
2004-09-05 17:39:54 +00:00
|
|
|
else
|
2006-09-18 19:22:40 +00:00
|
|
|
#endif
|
2007-09-08 11:15:27 +00:00
|
|
|
_gdi->drawBitmap(ptr, &_virtscr[kMainVirtScreen], x, ypos, width * 8, height, x - xpos, numstrip, flags);
|
2001-11-26 19:57:57 +00:00
|
|
|
}
|
SCUMM: Fix an original tapestry glitch in Indy3 VGA (Trac#3208)
The 256-color versions of Indy3 have a very strange vertical line on the
big tapestry that's in the middle of room 135, in Castle Brunwald.
It looks like an artist made some wrong click when redrawing this object
for the VGA versions, or maybe the compression routine for those images
had some bug. QA was probably rushed for this port, too, since Indy3 has
various oversights related to the VGA conversion. A similar problem was
fixed in commit 6735e3c0f006730831f020e31b3385ee55f58edb.
The tapestry glitch was a bit harder to fix, because the glitched line
hides several pixels with different colors, and because this resource is
in a compressed format. AFAICS, v3 games have no concept of transparent
pixels for background objects, so that simpler solution wouldn't work
either. We could also trim the leftmost OI strip (since the wall in the
background is fine), but I couldn't get this to safely work with the way
unkDecode11() works.
So I have redrawn a fixed OI_0324 with the old BMRP.EXE tool, diffed
the two resources and then added a small mechanism which patches (for
copyright reasons) the impacted bytes from the original resource, as
it is being read. This is a very low-level trick, so various checks
have been added to make sure that we're not corrupting something
(incl. any fan-made modified Indy3), and also in order to make the
workaround a bit easier to follow.
(The most obsessive players will notice that the tapestry still cuts
through a part of the column in the upper-right corner, but I'm only
interested in fixing the obvious problem which was right in the
middle of the room. Sorry if you wished you hadn't seen this.)
2022-09-25 21:13:55 +02:00
|
|
|
|
|
|
|
if (patchedBmpPtr)
|
|
|
|
delete[] patchedBmpPtr;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
void ScummEngine::clearRoomObjects() {
|
2003-01-26 10:57:01 +00:00
|
|
|
int i;
|
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.features & GF_SMALL_HEADER) {
|
2003-01-26 10:57:01 +00:00
|
|
|
for (i = 0; i < _numLocalObjects; i++) {
|
|
|
|
_objs[i].obj_nr = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < _numLocalObjects; i++) {
|
|
|
|
if (_objs[i].obj_nr < 1) // Optimise codepath
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Nuke all non-flObjects (flObjects are nuked in script.cpp)
|
|
|
|
if (_objs[i].fl_object_index == 0) {
|
|
|
|
_objs[i].obj_nr = 0;
|
|
|
|
} else {
|
|
|
|
// Nuke all unlocked flObjects
|
2006-09-17 20:36:48 +00:00
|
|
|
if (!_res->isLocked(rtFlObject, _objs[i].fl_object_index)) {
|
|
|
|
_res->nukeResource(rtFlObject, _objs[i].fl_object_index);
|
2003-01-26 10:57:01 +00:00
|
|
|
_objs[i].obj_nr = 0;
|
|
|
|
_objs[i].fl_object_index = 0;
|
2003-07-28 00:04:20 +00:00
|
|
|
}
|
2003-01-26 10:57:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-17 22:22:50 +00:00
|
|
|
void ScummEngine_v70he::resetRoomObjects() {
|
|
|
|
ScummEngine_v60he::resetRoomObjects();
|
|
|
|
restoreFlObjects();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScummEngine_v70he::clearRoomObjects() {
|
|
|
|
_numStoredFlObjects = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < _numLocalObjects; i++) {
|
|
|
|
if (_objs[i].obj_nr < 1) // Optimise codepath
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (_objs[i].fl_object_index != 0) {
|
|
|
|
if (!_res->isLocked(rtFlObject, _objs[i].fl_object_index)) {
|
|
|
|
_res->nukeResource(rtFlObject, _objs[i].fl_object_index);
|
|
|
|
} else {
|
|
|
|
storeFlObject(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_objs[i].fl_object_index = 0;
|
|
|
|
_objs[i].obj_nr = 0;
|
2005-10-14 02:13:33 +00:00
|
|
|
}
|
2006-09-17 22:22:50 +00:00
|
|
|
|
|
|
|
if (_currentRoom == 0)
|
|
|
|
restoreFlObjects();
|
2005-10-14 02:13:33 +00:00
|
|
|
}
|
|
|
|
|
2006-09-17 22:22:50 +00:00
|
|
|
void ScummEngine_v70he::storeFlObject(int slot) {
|
|
|
|
memcpy(&_storedFlObjects[_numStoredFlObjects], &_objs[slot], sizeof(_objs[slot]));
|
|
|
|
_numStoredFlObjects++;
|
|
|
|
if (_numStoredFlObjects > 100)
|
2010-09-18 10:55:16 +00:00
|
|
|
error("Too many flobjects saved on room transition");
|
2006-09-17 22:22:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScummEngine_v70he::restoreFlObjects() {
|
2005-10-14 02:13:33 +00:00
|
|
|
int i, slot;
|
|
|
|
|
|
|
|
for (i = 0; i < _numStoredFlObjects; i++) {
|
|
|
|
slot = findLocalObjectSlot();
|
|
|
|
memcpy(&_objs[slot], &_storedFlObjects[i], sizeof(_objs[slot]));
|
|
|
|
}
|
|
|
|
|
|
|
|
_numStoredFlObjects = 0;
|
|
|
|
}
|
|
|
|
|
2006-04-29 16:24:39 +00:00
|
|
|
void ScummEngine::resetRoomObjects() {
|
2002-04-11 17:19:16 +00:00
|
|
|
int i, j;
|
2001-10-09 14:30:12 +00:00
|
|
|
ObjectData *od;
|
2003-05-28 20:01:47 +00:00
|
|
|
const byte *ptr;
|
2001-10-09 14:30:12 +00:00
|
|
|
uint16 obim_id;
|
2003-05-28 20:01:47 +00:00
|
|
|
const byte *room, *searchptr, *rootptr;
|
|
|
|
const CodeHeader *cdhd;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2002-12-24 15:27:27 +00:00
|
|
|
room = getResourceAddress(rtRoom, _roomResource);
|
2018-05-17 12:40:02 +02:00
|
|
|
assert(room);
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2001-10-09 14:30:12 +00:00
|
|
|
if (_numObjectsInRoom == 0)
|
|
|
|
return;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2001-10-16 10:01:48 +00:00
|
|
|
if (_numObjectsInRoom > _numLocalObjects)
|
|
|
|
error("More than %d objects in room %d", _numLocalObjects, _roomResource);
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version == 8)
|
2002-12-24 12:49:25 +00:00
|
|
|
searchptr = rootptr = getResourceAddress(rtRoomScripts, _roomResource);
|
2002-12-24 12:09:11 +00:00
|
|
|
else
|
2002-12-24 12:49:25 +00:00
|
|
|
searchptr = rootptr = room;
|
2002-12-27 14:36:28 +00:00
|
|
|
assert(searchptr);
|
2002-12-24 12:09:11 +00:00
|
|
|
|
2003-01-12 07:30:17 +00:00
|
|
|
// Load in new room objects
|
2018-05-17 12:40:02 +02:00
|
|
|
ResourceIterator obcds(searchptr, false);
|
2003-01-12 07:30:17 +00:00
|
|
|
for (i = 0; i < _numObjectsInRoom; i++) {
|
|
|
|
od = &_objs[findLocalObjectSlot()];
|
|
|
|
|
2011-04-12 16:53:15 +02:00
|
|
|
ptr = obcds.findNext(MKTAG('O','B','C','D'));
|
2021-11-13 23:40:38 +02:00
|
|
|
if (ptr == nullptr)
|
2001-10-09 14:30:12 +00:00
|
|
|
error("Room %d missing object code block(s)", _roomResource);
|
|
|
|
|
2002-12-26 20:37:49 +00:00
|
|
|
od->OBCDoffset = ptr - rootptr;
|
2011-04-12 16:53:15 +02:00
|
|
|
cdhd = (const CodeHeader *)findResourceData(MKTAG('C','D','H','D'), ptr);
|
2002-03-05 20:43:26 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version >= 7)
|
2002-03-05 20:43:26 +00:00
|
|
|
od->obj_nr = READ_LE_UINT16(&(cdhd->v7.obj_id));
|
2006-02-20 16:51:30 +00:00
|
|
|
else if (_game.version == 6)
|
2002-04-11 17:19:16 +00:00
|
|
|
od->obj_nr = READ_LE_UINT16(&(cdhd->v6.obj_id));
|
2002-03-05 20:43:26 +00:00
|
|
|
else
|
2002-04-11 17:19:16 +00:00
|
|
|
od->obj_nr = READ_LE_UINT16(&(cdhd->v5.obj_id));
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2002-12-31 02:09:57 +00:00
|
|
|
if (_dumpScripts) {
|
2001-10-09 14:30:12 +00:00
|
|
|
char buf[32];
|
2022-10-23 15:26:54 +02:00
|
|
|
Common::sprintf_s(buf, "roomobj-%d-", _roomResource);
|
2011-04-12 16:53:15 +02:00
|
|
|
ptr = findResource(MKTAG('V','E','R','B'), ptr);
|
2001-10-09 14:30:12 +00:00
|
|
|
dumpResource(buf, od->obj_nr, ptr);
|
2002-12-31 02:09:57 +00:00
|
|
|
}
|
|
|
|
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2001-11-26 19:57:57 +00:00
|
|
|
searchptr = room;
|
2018-05-17 12:40:02 +02:00
|
|
|
ResourceIterator obims(room, false);
|
2002-04-11 17:19:16 +00:00
|
|
|
for (i = 0; i < _numObjectsInRoom; i++) {
|
2011-04-12 16:53:15 +02:00
|
|
|
ptr = obims.findNext(MKTAG('O','B','I','M'));
|
2021-11-13 23:40:38 +02:00
|
|
|
if (ptr == nullptr)
|
2001-10-09 14:30:12 +00:00
|
|
|
error("Room %d missing image blocks(s)", _roomResource);
|
|
|
|
|
2005-04-17 23:19:16 +00:00
|
|
|
obim_id = getObjectIdFromOBIM(ptr);
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2003-01-12 08:32:44 +00:00
|
|
|
for (j = 1; j < _numLocalObjects; j++) {
|
2002-04-11 17:19:16 +00:00
|
|
|
if (_objs[j].obj_nr == obim_id)
|
2002-12-26 20:37:49 +00:00
|
|
|
_objs[j].OBIMoffset = ptr - room;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-12 08:32:44 +00:00
|
|
|
for (i = 1; i < _numLocalObjects; i++) {
|
2003-01-12 10:20:09 +00:00
|
|
|
if (_objs[i].obj_nr && !_objs[i].fl_object_index)
|
2006-04-29 16:24:39 +00:00
|
|
|
resetRoomObject(&_objs[i], room);
|
2001-11-26 19:57:57 +00:00
|
|
|
}
|
2002-12-24 15:27:27 +00:00
|
|
|
}
|
2001-11-26 19:57:57 +00:00
|
|
|
|
2006-04-29 16:24:39 +00:00
|
|
|
void ScummEngine_v3old::resetRoomObjects() {
|
2003-04-12 02:09:00 +00:00
|
|
|
int i;
|
|
|
|
ObjectData *od;
|
2003-05-28 20:01:47 +00:00
|
|
|
const byte *room, *ptr;
|
2003-04-12 02:09:00 +00:00
|
|
|
|
|
|
|
room = getResourceAddress(rtRoom, _roomResource);
|
2018-05-17 12:40:02 +02:00
|
|
|
assert(room);
|
2003-04-12 02:09:00 +00:00
|
|
|
|
|
|
|
if (_numObjectsInRoom == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (_numObjectsInRoom > _numLocalObjects)
|
|
|
|
error("More than %d objects in room %d", _numLocalObjects, _roomResource);
|
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version <= 2)
|
2003-04-28 18:19:48 +00:00
|
|
|
ptr = room + 28;
|
|
|
|
else
|
|
|
|
ptr = room + 29;
|
|
|
|
|
2012-02-04 18:34:08 +01:00
|
|
|
// Default pointer of objects without image, in v0 version of Maniac Mansion
|
2006-03-13 03:52:26 +00:00
|
|
|
int defaultPtr = READ_LE_UINT16(ptr + 2 * _numObjectsInRoom);
|
|
|
|
|
2003-04-12 02:09:00 +00:00
|
|
|
for (i = 0; i < _numObjectsInRoom; i++) {
|
|
|
|
od = &_objs[findLocalObjectSlot()];
|
|
|
|
|
2006-05-29 12:45:11 +00:00
|
|
|
if (_game.version == 0 && READ_LE_UINT16(ptr) == defaultPtr)
|
2006-03-13 03:52:26 +00:00
|
|
|
od->OBIMoffset = 0;
|
|
|
|
else
|
|
|
|
od->OBIMoffset = READ_LE_UINT16(ptr);
|
|
|
|
|
2003-04-12 02:09:00 +00:00
|
|
|
od->OBCDoffset = READ_LE_UINT16(ptr + 2 * _numObjectsInRoom);
|
2006-04-29 16:24:39 +00:00
|
|
|
resetRoomObject(od, room);
|
2003-04-12 02:09:00 +00:00
|
|
|
|
|
|
|
ptr += 2;
|
2003-05-16 21:31:15 +00:00
|
|
|
|
|
|
|
if (_dumpScripts) {
|
|
|
|
char buf[32];
|
2022-10-23 15:26:54 +02:00
|
|
|
Common::sprintf_s(buf, "roomobj-%d-", _roomResource);
|
2003-05-16 21:31:15 +00:00
|
|
|
dumpResource(buf, od->obj_nr, room + od->OBCDoffset);
|
|
|
|
}
|
2003-04-12 02:09:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-29 16:24:39 +00:00
|
|
|
void ScummEngine_v4::resetRoomObjects() {
|
2002-04-11 17:19:16 +00:00
|
|
|
int i, j;
|
|
|
|
ObjectData *od;
|
2003-05-28 20:01:47 +00:00
|
|
|
const byte *ptr;
|
2002-04-11 17:19:16 +00:00
|
|
|
uint16 obim_id;
|
2003-06-26 00:47:39 +00:00
|
|
|
const byte *room;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2002-12-26 21:50:13 +00:00
|
|
|
room = getResourceAddress(rtRoom, _roomResource);
|
2018-05-17 12:40:02 +02:00
|
|
|
assert(room);
|
2002-04-11 17:19:16 +00:00
|
|
|
|
|
|
|
if (_numObjectsInRoom == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (_numObjectsInRoom > _numLocalObjects)
|
|
|
|
error("More than %d objects in room %d", _numLocalObjects, _roomResource);
|
|
|
|
|
2018-05-17 12:40:02 +02:00
|
|
|
ResourceIterator obcds(room, true);
|
2003-01-12 07:30:17 +00:00
|
|
|
for (i = 0; i < _numObjectsInRoom; i++) {
|
|
|
|
od = &_objs[findLocalObjectSlot()];
|
|
|
|
|
2011-04-12 16:53:15 +02:00
|
|
|
ptr = obcds.findNext(MKTAG('O','B','C','D'));
|
2021-11-13 23:40:38 +02:00
|
|
|
if (ptr == nullptr)
|
2002-04-11 17:19:16 +00:00
|
|
|
error("Room %d missing object code block(s)", _roomResource);
|
|
|
|
|
2002-12-26 20:37:49 +00:00
|
|
|
od->OBCDoffset = ptr - room;
|
2002-04-11 17:19:16 +00:00
|
|
|
od->obj_nr = READ_LE_UINT16(ptr + 6);
|
2002-12-31 02:09:57 +00:00
|
|
|
if (_dumpScripts) {
|
2002-04-11 17:19:16 +00:00
|
|
|
char buf[32];
|
2022-10-23 15:26:54 +02:00
|
|
|
Common::sprintf_s(buf, "roomobj-%d-", _roomResource);
|
2002-04-11 17:19:16 +00:00
|
|
|
dumpResource(buf, od->obj_nr, ptr);
|
2002-12-31 02:09:57 +00:00
|
|
|
}
|
2002-04-11 17:19:16 +00:00
|
|
|
}
|
2002-02-12 18:20:37 +00:00
|
|
|
|
2018-05-17 12:40:02 +02:00
|
|
|
ResourceIterator obims(room, true);
|
2002-04-11 17:19:16 +00:00
|
|
|
for (i = 0; i < _numObjectsInRoom; i++) {
|
2007-03-03 12:59:48 +00:00
|
|
|
// In the PC Engine version of Loom, there aren't image blocks
|
|
|
|
// for all objects.
|
2011-04-12 16:53:15 +02:00
|
|
|
ptr = obims.findNext(MKTAG('O','B','I','M'));
|
2021-11-13 23:40:38 +02:00
|
|
|
if (ptr == nullptr)
|
2007-03-03 12:59:48 +00:00
|
|
|
break;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
|
|
|
obim_id = READ_LE_UINT16(ptr + 6);
|
|
|
|
|
2003-01-12 08:32:44 +00:00
|
|
|
for (j = 1; j < _numLocalObjects; j++) {
|
2002-04-11 17:19:16 +00:00
|
|
|
if (_objs[j].obj_nr == obim_id)
|
2002-12-26 20:37:49 +00:00
|
|
|
_objs[j].OBIMoffset = ptr - room;
|
2002-04-11 17:19:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-12 08:32:44 +00:00
|
|
|
for (i = 1; i < _numLocalObjects; i++) {
|
2003-04-12 02:09:00 +00:00
|
|
|
if (_objs[i].obj_nr && !_objs[i].fl_object_index) {
|
2006-04-29 16:24:39 +00:00
|
|
|
resetRoomObject(&_objs[i], room);
|
2003-04-12 02:09:00 +00:00
|
|
|
}
|
2002-04-11 17:19:16 +00:00
|
|
|
}
|
2002-12-24 15:27:27 +00:00
|
|
|
}
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2007-02-25 11:38:19 +00:00
|
|
|
void ScummEngine_v0::resetRoomObject(ObjectData *od, const byte *room, const byte *searchptr) {
|
2005-09-14 04:18:29 +00:00
|
|
|
assert(room);
|
|
|
|
const byte *ptr = room + od->OBCDoffset;
|
|
|
|
ptr -= 2;
|
|
|
|
|
2012-01-16 22:32:46 +01:00
|
|
|
od->obj_nr = OBJECT_V0(*(ptr + 6), *(ptr + 7));
|
2005-09-14 04:18:29 +00:00
|
|
|
|
|
|
|
od->x_pos = *(ptr + 8) * 8;
|
|
|
|
od->y_pos = ((*(ptr + 9)) & 0x7F) * 8;
|
|
|
|
|
|
|
|
od->parentstate = (*(ptr + 9) & 0x80) ? 1 : 0;
|
|
|
|
od->parentstate *= 8;
|
|
|
|
|
|
|
|
od->width = *(ptr + 10) * 8;
|
|
|
|
|
|
|
|
od->parent = *(ptr + 11);
|
|
|
|
|
|
|
|
od->walk_x = *(ptr + 12) * 8;
|
|
|
|
od->walk_y = (*(ptr + 13) & 0x1f) * 8;
|
|
|
|
od->actordir = (*(ptr + 14)) & 7;
|
|
|
|
od->height = *(ptr + 14) & 0xf8;
|
|
|
|
}
|
|
|
|
|
2006-04-29 16:24:39 +00:00
|
|
|
void ScummEngine_v4::resetRoomObject(ObjectData *od, const byte *room, const byte *searchptr) {
|
2002-12-27 14:36:28 +00:00
|
|
|
assert(room);
|
2005-04-01 13:05:40 +00:00
|
|
|
const byte *ptr = room + od->OBCDoffset;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.features & GF_OLD_BUNDLE)
|
2005-04-01 13:05:40 +00:00
|
|
|
ptr -= 2;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2005-09-14 04:18:29 +00:00
|
|
|
od->obj_nr = READ_LE_UINT16(ptr + 6);
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2007-03-03 23:02:54 +00:00
|
|
|
if (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine) {
|
|
|
|
od->x_pos = *(ptr + 8) * 8;
|
|
|
|
od->y_pos = ((*(ptr + 9)) & 0x7F) * 8;
|
2003-04-12 02:09:00 +00:00
|
|
|
|
2009-10-22 11:33:05 +00:00
|
|
|
od->parentstate = (*(ptr + 9) & 0x80) ? 1 : 0;
|
2007-03-03 23:02:54 +00:00
|
|
|
od->width = *(ptr + 10) * 8;
|
2001-11-26 19:57:57 +00:00
|
|
|
|
2009-10-22 11:33:05 +00:00
|
|
|
// TODO: Where is parent data?
|
|
|
|
od->parent = 0;
|
|
|
|
od->walk_x = READ_LE_UINT16(ptr + 11);
|
|
|
|
od->walk_y = READ_LE_UINT16(ptr + 13);
|
2005-04-01 13:05:40 +00:00
|
|
|
od->actordir = (*(ptr + 15)) & 7;
|
|
|
|
od->height = *(ptr + 15) & 0xf8;
|
|
|
|
} else {
|
2007-03-03 23:02:54 +00:00
|
|
|
od->x_pos = *(ptr + 9) * 8;
|
|
|
|
od->y_pos = ((*(ptr + 10)) & 0x7F) * 8;
|
|
|
|
|
|
|
|
od->parentstate = (*(ptr + 10) & 0x80) ? 1 : 0;
|
|
|
|
if (_game.version <= 2)
|
|
|
|
od->parentstate *= 8;
|
|
|
|
|
|
|
|
od->width = *(ptr + 11) * 8;
|
|
|
|
|
|
|
|
od->parent = *(ptr + 12);
|
|
|
|
|
|
|
|
if (_game.version <= 2) {
|
|
|
|
od->walk_x = *(ptr + 13) * 8;
|
|
|
|
od->walk_y = (*(ptr + 14) & 0x1f) * 8;
|
|
|
|
od->actordir = (*(ptr + 15)) & 7;
|
|
|
|
od->height = *(ptr + 15) & 0xf8;
|
|
|
|
} else {
|
|
|
|
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) & 0xf8;
|
|
|
|
}
|
2005-04-01 13:05:40 +00:00
|
|
|
}
|
|
|
|
}
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2006-04-29 16:24:39 +00:00
|
|
|
void ScummEngine::resetRoomObject(ObjectData *od, const byte *room, const byte *searchptr) {
|
2021-11-13 23:40:38 +02:00
|
|
|
const CodeHeader *cdhd = nullptr;
|
|
|
|
const ImageHeader *imhd = nullptr;
|
2003-04-28 12:38:24 +00:00
|
|
|
|
2005-04-01 13:05:40 +00:00
|
|
|
assert(room);
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2021-11-13 23:40:38 +02:00
|
|
|
if (searchptr == nullptr) {
|
2018-05-17 12:40:02 +02:00
|
|
|
if (_game.version == 8) {
|
2002-12-27 14:36:28 +00:00
|
|
|
searchptr = getResourceAddress(rtRoomScripts, _roomResource);
|
2018-05-17 12:40:02 +02:00
|
|
|
assert(searchptr);
|
|
|
|
} else {
|
2002-12-27 14:36:28 +00:00
|
|
|
searchptr = room;
|
2018-05-17 12:40:02 +02:00
|
|
|
}
|
2002-12-27 14:36:28 +00:00
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2011-04-12 16:53:15 +02:00
|
|
|
cdhd = (const CodeHeader *)findResourceData(MKTAG('C','D','H','D'), searchptr + od->OBCDoffset);
|
2021-11-13 23:40:38 +02:00
|
|
|
if (cdhd == nullptr)
|
2002-12-24 12:27:35 +00:00
|
|
|
error("Room %d missing CDHD blocks(s)", _roomResource);
|
2005-02-15 03:32:07 +00:00
|
|
|
if (od->OBIMoffset)
|
2011-04-12 16:53:15 +02:00
|
|
|
imhd = (const ImageHeader *)findResourceData(MKTAG('I','M','H','D'), room + od->OBIMoffset);
|
2002-12-24 04:02:21 +00:00
|
|
|
|
2004-10-08 23:06:19 +00:00
|
|
|
od->flags = Gdi::dbAllowMaskOr;
|
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version == 8) {
|
2010-10-18 16:00:07 +00:00
|
|
|
assert(imhd);
|
2002-12-24 04:02:21 +00:00
|
|
|
od->obj_nr = READ_LE_UINT16(&(cdhd->v7.obj_id));
|
|
|
|
|
|
|
|
od->parent = cdhd->v7.parent;
|
|
|
|
od->parentstate = cdhd->v7.parentstate;
|
|
|
|
|
2002-12-25 07:48:37 +00:00
|
|
|
od->x_pos = (int)READ_LE_UINT32(&imhd->v8.x_pos);
|
|
|
|
od->y_pos = (int)READ_LE_UINT32(&imhd->v8.y_pos);
|
|
|
|
od->width = (uint)READ_LE_UINT32(&imhd->v8.width);
|
|
|
|
od->height = (uint)READ_LE_UINT32(&imhd->v8.height);
|
2005-04-01 13:05:40 +00:00
|
|
|
// HACK: This is done since an angle doesn't fit into a byte (360 > 256)
|
2003-03-02 15:51:56 +00:00
|
|
|
od->actordir = toSimpleDir(1, READ_LE_UINT32(&imhd->v8.actordir));
|
2004-10-08 23:06:19 +00:00
|
|
|
if (FROM_LE_32(imhd->v8.version) == 801)
|
|
|
|
od->flags = ((((byte)READ_LE_UINT32(&imhd->v8.flags)) & 16) == 0) ? Gdi::dbAllowMaskOr : 0;
|
2002-12-24 04:02:21 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
} else if (_game.version == 7) {
|
2010-10-18 16:00:07 +00:00
|
|
|
assert(imhd);
|
2002-03-05 20:43:26 +00:00
|
|
|
od->obj_nr = READ_LE_UINT16(&(cdhd->v7.obj_id));
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2002-03-05 23:05:55 +00:00
|
|
|
od->parent = cdhd->v7.parent;
|
|
|
|
od->parentstate = cdhd->v7.parentstate;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2002-03-16 18:58:51 +00:00
|
|
|
od->x_pos = READ_LE_UINT16(&imhd->v7.x_pos);
|
|
|
|
od->y_pos = READ_LE_UINT16(&imhd->v7.y_pos);
|
2002-04-11 17:19:16 +00:00
|
|
|
od->width = READ_LE_UINT16(&imhd->v7.width);
|
2002-03-16 18:58:51 +00:00
|
|
|
od->height = READ_LE_UINT16(&imhd->v7.height);
|
2004-10-08 07:34:06 +00:00
|
|
|
od->actordir = (byte)READ_LE_UINT16(&imhd->v7.actordir);
|
2001-11-26 19:57:57 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
} else if (_game.version == 6) {
|
2002-12-24 04:02:21 +00:00
|
|
|
od->obj_nr = READ_LE_UINT16(&(cdhd->v6.obj_id));
|
|
|
|
|
|
|
|
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;
|
2004-10-08 23:06:19 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.heversion >= 60 && imhd)
|
2004-10-08 23:06:19 +00:00
|
|
|
od->flags = ((imhd->old.flags & 1) != 0) ? Gdi::dbAllowMaskOr : 0;
|
2004-09-26 15:25:58 +00:00
|
|
|
|
2002-12-24 04:02:21 +00:00
|
|
|
} else {
|
|
|
|
od->obj_nr = READ_LE_UINT16(&(cdhd->v5.obj_id));
|
|
|
|
|
2003-11-16 20:52:57 +00:00
|
|
|
od->width = cdhd->v5.w * 8;
|
|
|
|
od->height = cdhd->v5.h * 8;
|
|
|
|
od->x_pos = cdhd->v5.x * 8;
|
|
|
|
od->y_pos = cdhd->v5.y * 8;
|
2002-12-24 04:02:21 +00:00
|
|
|
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;
|
2002-03-05 23:05:55 +00:00
|
|
|
}
|
2002-12-24 04:02:21 +00:00
|
|
|
|
2001-11-26 19:57:57 +00:00
|
|
|
od->fl_object_index = 0;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 14:30:32 +00:00
|
|
|
void ScummEngine::updateObjectStates() {
|
2001-10-09 14:30:12 +00:00
|
|
|
int i;
|
2001-10-16 10:01:48 +00:00
|
|
|
ObjectData *od = &_objs[1];
|
2003-01-12 08:32:44 +00:00
|
|
|
for (i = 1; i < _numLocalObjects; i++, od++) {
|
2012-01-03 22:10:50 +01:00
|
|
|
// V0 MM, objects with type == 1 are room objects (room specific objects, non-pickup)
|
2012-01-16 22:32:46 +01:00
|
|
|
if (_game.version == 0 && OBJECT_V0_TYPE(od->obj_nr) == kObjectV0TypeBG)
|
2009-07-25 06:27:41 +00:00
|
|
|
continue;
|
|
|
|
|
2003-01-12 07:30:17 +00:00
|
|
|
if (od->obj_nr > 0)
|
2003-06-16 14:45:23 +00:00
|
|
|
od->state = getState(od->obj_nr);
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
void ScummEngine::processDrawQue() {
|
2001-10-09 14:30:12 +00:00
|
|
|
int i, j;
|
2002-04-11 17:19:16 +00:00
|
|
|
for (i = 0; i < _drawObjectQueNr; i++) {
|
2001-10-09 14:30:12 +00:00
|
|
|
j = _drawObjectQue[i];
|
|
|
|
if (j)
|
2002-04-11 17:19:16 +00:00
|
|
|
drawObject(j, 0);
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
_drawObjectQueNr = 0;
|
|
|
|
}
|
|
|
|
|
2004-01-11 21:48:31 +00:00
|
|
|
void ScummEngine::addObjectToDrawQue(int object) {
|
|
|
|
if ((unsigned int)_drawObjectQueNr >= ARRAYSIZE(_drawObjectQue))
|
|
|
|
error("Draw Object Que overflow");
|
|
|
|
_drawObjectQue[_drawObjectQueNr++] = object;
|
|
|
|
}
|
|
|
|
|
2004-09-06 01:10:31 +00:00
|
|
|
void ScummEngine::removeObjectFromDrawQue(int object) {
|
2004-09-12 10:51:00 +00:00
|
|
|
if (_drawObjectQueNr <= 0)
|
2004-09-06 01:10:31 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < _drawObjectQueNr; i++) {
|
2004-09-06 07:06:11 +00:00
|
|
|
if (_drawObjectQue[i] == object)
|
2004-09-06 01:10:31 +00:00
|
|
|
_drawObjectQue[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-11 21:48:31 +00:00
|
|
|
void ScummEngine::clearDrawObjectQueue() {
|
|
|
|
_drawObjectQueNr = 0;
|
|
|
|
}
|
|
|
|
|
2005-04-28 22:34:56 +00:00
|
|
|
void ScummEngine::clearDrawQueues() {
|
|
|
|
clearDrawObjectQueue();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScummEngine_v6::clearDrawQueues() {
|
|
|
|
ScummEngine::clearDrawQueues();
|
|
|
|
|
|
|
|
_blastObjectQueuePos = 0;
|
|
|
|
}
|
|
|
|
|
2008-05-06 03:00:26 +00:00
|
|
|
#ifdef ENABLE_HE
|
2007-12-27 11:40:29 +00:00
|
|
|
void ScummEngine_v71he::clearDrawQueues() {
|
2005-04-28 22:34:56 +00:00
|
|
|
ScummEngine_v6::clearDrawQueues();
|
|
|
|
|
2005-05-23 02:00:49 +00:00
|
|
|
_wiz->polygonClear();
|
2005-04-28 22:34:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScummEngine_v80he::clearDrawQueues() {
|
2008-01-05 17:43:33 +00:00
|
|
|
ScummEngine_v71he::clearDrawQueues();
|
2005-04-28 22:34:56 +00:00
|
|
|
|
2005-05-23 02:00:49 +00:00
|
|
|
_wiz->clearWizBuffer();
|
2005-04-28 22:34:56 +00:00
|
|
|
}
|
2005-05-14 14:06:37 +00:00
|
|
|
#endif
|
2005-04-28 22:34:56 +00:00
|
|
|
|
2004-01-11 20:15:05 +00:00
|
|
|
/**
|
2004-01-11 20:42:40 +00:00
|
|
|
* Mark the rectangle covered by the given object as dirty, thus eventually
|
|
|
|
* ensuring a redraw of that area. This function is typically invoked when an
|
|
|
|
* object gets removed from the current room, or when its state changed.
|
2004-01-11 20:15:05 +00:00
|
|
|
*/
|
2004-01-11 20:42:40 +00:00
|
|
|
void ScummEngine::markObjectRectAsDirty(int obj) {
|
|
|
|
int i, strip;
|
2016-07-19 18:55:27 +10:00
|
|
|
++_V0Delay._objectRedrawCount;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2003-01-12 08:32:44 +00:00
|
|
|
for (i = 1; i < _numLocalObjects; i++) {
|
2002-04-11 17:19:16 +00:00
|
|
|
if (_objs[i].obj_nr == (uint16)obj) {
|
2001-11-26 19:57:57 +00:00
|
|
|
if (_objs[i].width != 0) {
|
2004-01-11 20:42:40 +00:00
|
|
|
const int minStrip = MAX(_screenStartStrip, _objs[i].x_pos / 8);
|
|
|
|
const int maxStrip = MIN(_screenEndStrip+1, _objs[i].x_pos / 8 + _objs[i].width / 8);
|
|
|
|
for (strip = minStrip; strip < maxStrip; strip++) {
|
2016-07-19 18:55:27 +10:00
|
|
|
++_V0Delay._objectStripRedrawCount;
|
2003-01-17 15:23:27 +00:00
|
|
|
setGfxUsageBit(strip, USAGE_BIT_DIRTY);
|
|
|
|
}
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2004-09-18 22:42:45 +00:00
|
|
|
_bgNeedsRedraw = true;
|
2001-10-09 14:30:12 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
const byte *ScummEngine::getObjOrActorName(int obj) {
|
2001-10-09 14:30:12 +00:00
|
|
|
byte *objptr;
|
2002-06-25 02:04:43 +00:00
|
|
|
int i;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2012-01-22 22:58:10 +01:00
|
|
|
if (objIsActor(obj))
|
|
|
|
return derefActor(objToActor(obj), "getObjOrActorName")->getActorName();
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2004-03-17 01:50:15 +00:00
|
|
|
for (i = 0; i < _numNewNames; i++) {
|
|
|
|
if (_newNames[i] == obj) {
|
|
|
|
debug(5, "Found new name for object %d at _newNames[%d]", obj, i);
|
|
|
|
return getResourceAddress(rtObjectName, i);
|
2002-06-25 02:04:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-07 16:08:55 +01:00
|
|
|
objptr = getOBCDFromObject(obj, true);
|
2021-11-13 23:40:38 +02:00
|
|
|
if (objptr == nullptr)
|
|
|
|
return nullptr;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.features & GF_SMALL_HEADER) {
|
2003-06-20 11:14:18 +00:00
|
|
|
byte offset = 0;
|
2003-05-31 11:57:18 +00:00
|
|
|
|
2006-05-29 12:45:11 +00:00
|
|
|
if (_game.version == 0)
|
2006-03-02 05:04:40 +00:00
|
|
|
offset = *(objptr + 13);
|
|
|
|
else if (_game.version <= 2)
|
2003-05-31 11:57:18 +00:00
|
|
|
offset = *(objptr + 14);
|
2006-02-20 16:51:30 +00:00
|
|
|
else if (_game.features & GF_OLD_BUNDLE)
|
2003-05-31 11:57:18 +00:00
|
|
|
offset = *(objptr + 16);
|
2009-10-23 12:50:51 +00:00
|
|
|
else if (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine)
|
|
|
|
offset = *(objptr + 16) + 17;
|
2003-05-31 11:57:18 +00:00
|
|
|
else
|
2003-06-20 11:14:18 +00:00
|
|
|
offset = *(objptr + 18);
|
2003-05-31 11:57:18 +00:00
|
|
|
|
|
|
|
return (objptr + offset);
|
|
|
|
}
|
|
|
|
|
2011-04-12 16:53:15 +02:00
|
|
|
return findResourceData(MKTAG('O','B','N','A'), objptr);
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2004-03-17 01:50:15 +00:00
|
|
|
void ScummEngine::setObjectName(int obj) {
|
|
|
|
int i;
|
|
|
|
|
2012-01-22 22:58:10 +01:00
|
|
|
if (objIsActor(obj))
|
2004-03-17 01:50:15 +00:00
|
|
|
error("Can't set actor %d name with new-name-of", obj);
|
|
|
|
|
|
|
|
for (i = 0; i < _numNewNames; i++) {
|
|
|
|
if (_newNames[i] == obj) {
|
2006-09-17 20:36:48 +00:00
|
|
|
_res->nukeResource(rtObjectName, i);
|
2004-03-17 01:50:15 +00:00
|
|
|
_newNames[i] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < _numNewNames; i++) {
|
|
|
|
if (_newNames[i] == 0) {
|
2021-11-13 23:40:38 +02:00
|
|
|
loadPtrToResource(rtObjectName, i, nullptr);
|
2004-03-17 01:50:15 +00:00
|
|
|
_newNames[i] = obj;
|
|
|
|
runInventoryScript(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
error("New name of %d overflows name table (max = %d)", obj, _numNewNames);
|
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
uint32 ScummEngine::getOBCDOffs(int object) const {
|
2001-10-09 14:30:12 +00:00
|
|
|
int i;
|
|
|
|
|
2012-01-07 16:08:55 +01:00
|
|
|
if ((_game.version != 0 || OBJECT_V0_TYPE(object) == 0) &&
|
|
|
|
_objectOwnerTable[object] != OF_OWNER_ROOM)
|
2001-10-09 14:30:12 +00:00
|
|
|
return 0;
|
2009-07-25 06:27:41 +00:00
|
|
|
|
2003-01-12 08:32:44 +00:00
|
|
|
for (i = (_numLocalObjects-1); i > 0; i--) {
|
2012-01-16 22:32:46 +01:00
|
|
|
if (_objs[i].obj_nr == object) {
|
2002-04-11 17:19:16 +00:00
|
|
|
if (_objs[i].fl_object_index != 0)
|
2001-10-09 14:30:12 +00:00
|
|
|
return 8;
|
2002-12-26 20:37:49 +00:00
|
|
|
return _objs[i].OBCDoffset;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-01-07 16:08:55 +01:00
|
|
|
byte *ScummEngine::getOBCDFromObject(int obj, bool v0CheckInventory) {
|
2001-10-09 14:30:12 +00:00
|
|
|
int i;
|
2003-06-26 13:55:01 +00:00
|
|
|
byte *ptr;
|
2001-10-09 14:30:12 +00:00
|
|
|
|
2012-01-07 16:08:55 +01:00
|
|
|
if ((_game.version != 0 || OBJECT_V0_TYPE(obj) == 0) &&
|
2012-09-26 04:17:31 +02:00
|
|
|
_objectOwnerTable[obj] != OF_OWNER_ROOM)
|
2012-01-07 16:08:55 +01:00
|
|
|
{
|
|
|
|
if (_game.version == 0 && !v0CheckInventory)
|
2021-11-13 23:40:38 +02:00
|
|
|
return nullptr;
|
2003-12-26 23:11:35 +00:00
|
|
|
for (i = 0; i < _numInventory; i++) {
|
2001-10-09 14:30:12 +00:00
|
|
|
if (_inventory[i] == obj)
|
2001-11-05 19:21:49 +00:00
|
|
|
return getResourceAddress(rtInventory, i);
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
} else {
|
2003-01-12 08:32:44 +00:00
|
|
|
for (i = (_numLocalObjects-1); i > 0; --i) {
|
2012-01-16 22:32:46 +01:00
|
|
|
if (_objs[i].obj_nr == obj) {
|
2003-06-26 13:55:01 +00:00
|
|
|
if (_objs[i].fl_object_index) {
|
|
|
|
assert(_objs[i].OBCDoffset == 8);
|
|
|
|
ptr = getResourceAddress(rtFlObject, _objs[i].fl_object_index);
|
2006-02-20 16:51:30 +00:00
|
|
|
} else if (_game.version == 8)
|
2003-06-26 13:55:01 +00:00
|
|
|
ptr = getResourceAddress(rtRoomScripts, _roomResource);
|
2002-12-26 20:37:49 +00:00
|
|
|
else
|
2003-06-26 13:55:01 +00:00
|
|
|
ptr = getResourceAddress(rtRoom, _roomResource);
|
|
|
|
assert(ptr);
|
|
|
|
return ptr + _objs[i].OBCDoffset;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-13 23:40:38 +02:00
|
|
|
return nullptr;
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2005-06-23 14:10:52 +00:00
|
|
|
const byte *ScummEngine::getOBIMFromObjectData(const ObjectData &od) {
|
2003-06-26 01:46:41 +00:00
|
|
|
const byte *ptr;
|
|
|
|
|
|
|
|
if (od.fl_object_index) {
|
|
|
|
ptr = getResourceAddress(rtFlObject, od.fl_object_index);
|
2011-04-12 16:53:15 +02:00
|
|
|
ptr = findResource(MKTAG('O','B','I','M'), ptr);
|
2003-06-26 01:46:41 +00:00
|
|
|
} else {
|
|
|
|
ptr = getResourceAddress(rtRoom, _roomResource);
|
|
|
|
if (ptr)
|
|
|
|
ptr += od.OBIMoffset;
|
|
|
|
}
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2006-02-25 02:12:58 +00:00
|
|
|
static const uint32 IMxx_tags[] = {
|
2011-04-12 16:53:15 +02:00
|
|
|
MKTAG('I','M','0','0'),
|
|
|
|
MKTAG('I','M','0','1'),
|
|
|
|
MKTAG('I','M','0','2'),
|
|
|
|
MKTAG('I','M','0','3'),
|
|
|
|
MKTAG('I','M','0','4'),
|
|
|
|
MKTAG('I','M','0','5'),
|
|
|
|
MKTAG('I','M','0','6'),
|
|
|
|
MKTAG('I','M','0','7'),
|
|
|
|
MKTAG('I','M','0','8'),
|
|
|
|
MKTAG('I','M','0','9'),
|
|
|
|
MKTAG('I','M','0','A'),
|
|
|
|
MKTAG('I','M','0','B'),
|
|
|
|
MKTAG('I','M','0','C'),
|
|
|
|
MKTAG('I','M','0','D'),
|
|
|
|
MKTAG('I','M','0','E'),
|
|
|
|
MKTAG('I','M','0','F'),
|
|
|
|
MKTAG('I','M','1','0')
|
2006-02-25 02:12:58 +00:00
|
|
|
};
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
const byte *ScummEngine::getObjectImage(const byte *ptr, int state) {
|
2003-06-26 01:46:41 +00:00
|
|
|
assert(ptr);
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.features & GF_OLD_BUNDLE)
|
2003-06-26 01:46:41 +00:00
|
|
|
ptr += 0;
|
2006-02-20 16:51:30 +00:00
|
|
|
else if (_game.features & GF_SMALL_HEADER) {
|
2003-06-26 01:46:41 +00:00
|
|
|
ptr += 8;
|
2006-02-20 16:51:30 +00:00
|
|
|
} else if (_game.version == 8) {
|
2003-06-26 01:46:41 +00:00
|
|
|
// The OBIM contains an IMAG, which in turn contains a WRAP, which contains
|
|
|
|
// an OFFS chunk and multiple BOMP/SMAP chunks. To find the right BOMP/SMAP,
|
|
|
|
// we use the offsets in the OFFS chunk,
|
2011-04-12 16:53:15 +02:00
|
|
|
ptr = findResource(MKTAG('I','M','A','G'), ptr);
|
2003-06-26 01:46:41 +00:00
|
|
|
if (!ptr)
|
2021-11-13 23:40:38 +02:00
|
|
|
return nullptr;
|
2003-06-26 01:46:41 +00:00
|
|
|
|
2011-04-12 16:53:15 +02:00
|
|
|
ptr = findResource(MKTAG('W','R','A','P'), ptr);
|
2003-06-26 01:46:41 +00:00
|
|
|
if (!ptr)
|
2021-11-13 23:40:38 +02:00
|
|
|
return nullptr;
|
2003-06-26 01:46:41 +00:00
|
|
|
|
2011-04-12 16:53:15 +02:00
|
|
|
ptr = findResource(MKTAG('O','F','F','S'), ptr);
|
2003-06-26 01:46:41 +00:00
|
|
|
if (!ptr)
|
2021-11-13 23:40:38 +02:00
|
|
|
return nullptr;
|
2003-06-26 01:46:41 +00:00
|
|
|
|
|
|
|
// Get the address of the specified SMAP (corresponding to IMxx)
|
|
|
|
ptr += READ_LE_UINT32(ptr + 4 + 4*state);
|
|
|
|
} else {
|
|
|
|
ptr = findResource(IMxx_tags[state], ptr);
|
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2003-06-26 01:46:41 +00:00
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2005-04-17 23:24:31 +00:00
|
|
|
int ScummEngine::getObjectImageCount(int object) {
|
|
|
|
const byte *ptr;
|
|
|
|
const ImageHeader *imhd;
|
|
|
|
int objnum;
|
|
|
|
|
|
|
|
objnum = getObjectIndex(object);
|
2005-04-25 03:45:37 +00:00
|
|
|
if (objnum == -1)
|
2005-04-17 23:24:31 +00:00
|
|
|
return 0;
|
|
|
|
|
2005-06-23 14:10:52 +00:00
|
|
|
ptr = getOBIMFromObjectData(_objs[objnum]);
|
2011-04-12 16:53:15 +02:00
|
|
|
imhd = (const ImageHeader *)findResourceData(MKTAG('I','M','H','D'), ptr);
|
2005-04-17 23:24:31 +00:00
|
|
|
if (!imhd)
|
|
|
|
return 0;
|
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version == 8) {
|
2005-04-17 23:24:31 +00:00
|
|
|
return (READ_LE_UINT32(&imhd->v8.image_count));
|
2006-02-20 16:51:30 +00:00
|
|
|
} else if (_game.version == 7) {
|
2005-04-17 23:24:31 +00:00
|
|
|
return(READ_LE_UINT16(&imhd->v7.image_count));
|
|
|
|
} else {
|
|
|
|
return (READ_LE_UINT16(&imhd->old.image_count));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-06 03:00:26 +00:00
|
|
|
#ifdef ENABLE_SCUMM_7_8
|
2005-04-17 23:24:31 +00:00
|
|
|
int ScummEngine_v8::getObjectIdFromOBIM(const byte *obim) {
|
|
|
|
// In V8, IMHD has no obj_id, but rather a name string. We map the name
|
|
|
|
// back to an object id using a table derived from the DOBJ resource.
|
2011-04-12 16:53:15 +02:00
|
|
|
const ImageHeader *imhd = (const ImageHeader *)findResourceData(MKTAG('I','M','H','D'), obim);
|
2005-04-23 16:52:11 +00:00
|
|
|
ObjectNameId *found = (ObjectNameId *)bsearch(imhd->v8.name, _objectIDMap, _objectIDMapSize,
|
|
|
|
sizeof(ObjectNameId), (int (*)(const void*, const void*))strcmp);
|
|
|
|
assert(found);
|
|
|
|
return found->id;
|
2005-04-17 23:24:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int ScummEngine_v7::getObjectIdFromOBIM(const byte *obim) {
|
2011-04-12 16:53:15 +02:00
|
|
|
const ImageHeader *imhd = (const ImageHeader *)findResourceData(MKTAG('I','M','H','D'), obim);
|
2005-04-17 23:24:31 +00:00
|
|
|
return READ_LE_UINT16(&imhd->v7.obj_id);
|
|
|
|
}
|
2005-05-14 22:56:41 +00:00
|
|
|
#endif
|
2005-04-17 23:24:31 +00:00
|
|
|
|
|
|
|
int ScummEngine::getObjectIdFromOBIM(const byte *obim) {
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.features & GF_SMALL_HEADER)
|
2005-04-17 23:24:31 +00:00
|
|
|
return READ_LE_UINT16(obim + 6);
|
|
|
|
|
2011-04-12 16:53:15 +02:00
|
|
|
const ImageHeader *imhd = (const ImageHeader *)findResourceData(MKTAG('I','M','H','D'), obim);
|
2005-04-17 23:24:31 +00:00
|
|
|
return READ_LE_UINT16(&imhd->old.obj_id);
|
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
void ScummEngine::findObjectInRoom(FindObjectInRoom *fo, byte findWhat, uint id, uint room) {
|
2003-04-12 12:58:20 +00:00
|
|
|
|
2003-05-28 20:01:47 +00:00
|
|
|
const CodeHeader *cdhd;
|
2001-11-26 19:57:57 +00:00
|
|
|
int i, numobj;
|
2003-05-28 20:01:47 +00:00
|
|
|
const byte *roomptr, *obcdptr, *obimptr, *searchptr;
|
2002-03-05 20:43:26 +00:00
|
|
|
int id2;
|
2005-04-17 23:19:16 +00:00
|
|
|
int obim_id;
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2005-06-23 14:10:52 +00:00
|
|
|
id2 = getObjectIndex(id);
|
|
|
|
if (findWhat & foCheckAlreadyLoaded && id2 != -1) {
|
2006-02-20 16:51:30 +00:00
|
|
|
assert(_game.version >= 6);
|
2005-06-23 14:10:52 +00:00
|
|
|
if (findWhat & foCodeHeader) {
|
|
|
|
fo->obcd = obcdptr = getOBCDFromObject(id);
|
|
|
|
assert(obcdptr);
|
2011-04-12 16:53:15 +02:00
|
|
|
fo->cdhd = (const CodeHeader *)findResourceData(MKTAG('C','D','H','D'), obcdptr);
|
2005-06-23 14:10:52 +00:00
|
|
|
}
|
|
|
|
if (findWhat & foImageHeader) {
|
|
|
|
fo->obim = obimptr = getOBIMFromObjectData(_objs[id2]);
|
|
|
|
assert(obimptr);
|
2003-04-12 12:58:20 +00:00
|
|
|
}
|
2001-10-09 14:30:12 +00:00
|
|
|
return;
|
|
|
|
}
|
2001-11-26 19:57:57 +00:00
|
|
|
|
|
|
|
fo->roomptr = roomptr = getResourceAddress(rtRoom, room);
|
2002-04-19 16:26:44 +00:00
|
|
|
if (!roomptr)
|
|
|
|
error("findObjectInRoom: failed getting roomptr to %d", room);
|
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.features & GF_OLD_BUNDLE) {
|
2003-04-12 12:58:20 +00:00
|
|
|
numobj = roomptr[20];
|
|
|
|
} else {
|
2011-04-12 16:53:15 +02:00
|
|
|
const RoomHeader *roomhdr = (const RoomHeader *)findResourceData(MKTAG('R','M','H','D'), roomptr);
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version == 8)
|
2003-04-12 12:58:20 +00:00
|
|
|
numobj = READ_LE_UINT32(&(roomhdr->v8.numObjects));
|
2006-02-20 16:51:30 +00:00
|
|
|
else if (_game.version == 7)
|
2003-04-12 12:58:20 +00:00
|
|
|
numobj = READ_LE_UINT16(&(roomhdr->v7.numObjects));
|
|
|
|
else
|
|
|
|
numobj = READ_LE_UINT16(&(roomhdr->old.numObjects));
|
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2002-04-11 17:19:16 +00:00
|
|
|
if (numobj == 0)
|
2001-11-26 19:57:57 +00:00
|
|
|
error("findObjectInRoom: No object found in room %d", room);
|
2001-11-06 21:41:56 +00:00
|
|
|
if (numobj > _numLocalObjects)
|
2002-07-07 20:25:23 +00:00
|
|
|
error("findObjectInRoom: More (%d) than %d objects in room %d", numobj, _numLocalObjects, room);
|
2001-11-26 19:57:57 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.features & GF_OLD_BUNDLE) {
|
|
|
|
if (_game.version <= 2)
|
2003-04-28 18:19:48 +00:00
|
|
|
searchptr = roomptr + 28;
|
|
|
|
else
|
|
|
|
searchptr = roomptr + 29;
|
|
|
|
|
2003-04-12 12:58:20 +00:00
|
|
|
for (i = 0; i < numobj; i++) {
|
|
|
|
obimptr = roomptr + READ_LE_UINT16(searchptr);
|
2005-04-10 01:42:00 +00:00
|
|
|
obcdptr = roomptr + READ_LE_UINT16(searchptr + 2 * numobj);
|
2003-04-12 12:58:20 +00:00
|
|
|
id2 = READ_LE_UINT16(obcdptr + 4);
|
|
|
|
|
|
|
|
if (id2 == (uint16)id) {
|
|
|
|
if (findWhat & foCodeHeader) {
|
|
|
|
fo->obcd = obcdptr;
|
2007-09-11 09:20:39 +00:00
|
|
|
// We assume that the code header starts at a fixed offset.
|
|
|
|
// A bit hackish, but works reasonably well.
|
|
|
|
fo->cdhd = (const CodeHeader *)(obcdptr + 10);
|
2003-04-12 12:58:20 +00:00
|
|
|
}
|
|
|
|
if (findWhat & foImageHeader) {
|
|
|
|
fo->obim = obimptr;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2003-04-13 21:47:48 +00:00
|
|
|
searchptr += 2;
|
2003-04-12 12:58:20 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-11-26 19:57:57 +00:00
|
|
|
if (findWhat & foCodeHeader) {
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version == 8)
|
2003-01-12 21:46:58 +00:00
|
|
|
searchptr = getResourceAddress(rtRoomScripts, room);
|
|
|
|
else
|
|
|
|
searchptr = roomptr;
|
2002-12-27 14:36:28 +00:00
|
|
|
assert(searchptr);
|
2006-02-20 16:51:30 +00:00
|
|
|
ResourceIterator obcds(searchptr, (_game.features & GF_SMALL_HEADER) != 0);
|
2004-09-24 20:37:24 +00:00
|
|
|
for (i = 0; i < numobj; i++) {
|
2011-04-12 16:53:15 +02:00
|
|
|
obcdptr = obcds.findNext(MKTAG('O','B','C','D'));
|
2021-11-13 23:40:38 +02:00
|
|
|
if (obcdptr == nullptr)
|
2001-11-26 19:57:57 +00:00
|
|
|
error("findObjectInRoom: Not enough code blocks in room %d", room);
|
2011-04-12 16:53:15 +02:00
|
|
|
cdhd = (const CodeHeader *)findResourceData(MKTAG('C','D','H','D'), obcdptr);
|
2002-12-25 11:59:55 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.features & GF_SMALL_HEADER)
|
2002-12-25 11:59:55 +00:00
|
|
|
id2 = READ_LE_UINT16(obcdptr + 6);
|
2006-02-20 16:51:30 +00:00
|
|
|
else if (_game.version >= 7)
|
2002-12-25 11:59:55 +00:00
|
|
|
id2 = READ_LE_UINT16(&(cdhd->v7.obj_id));
|
2006-02-20 16:51:30 +00:00
|
|
|
else if (_game.version == 6)
|
2002-12-25 11:59:55 +00:00
|
|
|
id2 = READ_LE_UINT16(&(cdhd->v6.obj_id));
|
|
|
|
else
|
|
|
|
id2 = READ_LE_UINT16(&(cdhd->v5.obj_id));
|
|
|
|
|
|
|
|
if (id2 == (uint16)id) {
|
|
|
|
fo->obcd = obcdptr;
|
2003-04-12 12:58:20 +00:00
|
|
|
fo->cdhd = cdhd;
|
2002-12-25 11:59:55 +00:00
|
|
|
break;
|
2002-04-11 17:19:16 +00:00
|
|
|
}
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
2004-09-24 20:37:24 +00:00
|
|
|
if (i == numobj)
|
|
|
|
error("findObjectInRoom: Object %d not found in room %d", id, room);
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2002-12-25 03:48:27 +00:00
|
|
|
roomptr = fo->roomptr;
|
2001-11-26 19:57:57 +00:00
|
|
|
if (findWhat & foImageHeader) {
|
2006-02-20 16:51:30 +00:00
|
|
|
ResourceIterator obims(roomptr, (_game.features & GF_SMALL_HEADER) != 0);
|
2004-09-24 20:37:24 +00:00
|
|
|
for (i = 0; i < numobj; i++) {
|
2011-04-12 16:53:15 +02:00
|
|
|
obimptr = obims.findNext(MKTAG('O','B','I','M'));
|
2021-11-13 23:40:38 +02:00
|
|
|
if (obimptr == nullptr)
|
2001-11-26 19:57:57 +00:00
|
|
|
error("findObjectInRoom: Not enough image blocks in room %d", room);
|
2005-04-17 23:19:16 +00:00
|
|
|
obim_id = getObjectIdFromOBIM(obimptr);
|
2002-12-25 11:59:55 +00:00
|
|
|
|
2005-04-17 23:19:16 +00:00
|
|
|
if (obim_id == (uint16)id) {
|
2002-12-25 11:59:55 +00:00
|
|
|
fo->obim = obimptr;
|
|
|
|
break;
|
2002-04-11 17:19:16 +00:00
|
|
|
}
|
2001-11-26 19:57:57 +00:00
|
|
|
}
|
2004-09-24 20:37:24 +00:00
|
|
|
if (i == numobj)
|
|
|
|
error("findObjectInRoom: Object %d image not found in room %d", id, room);
|
2001-11-26 19:57:57 +00:00
|
|
|
}
|
2001-10-09 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2012-02-10 22:58:59 +01:00
|
|
|
bool ScummEngine_v0::objIsActor(int obj) {
|
2012-01-22 22:58:10 +01:00
|
|
|
// object IDs < _numActors are used in v0 for objects too (e.g. hamster)
|
2012-02-10 22:58:59 +01:00
|
|
|
return OBJECT_V0_TYPE(obj) == kObjectV0TypeActor;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ScummEngine_v0::objToActor(int obj) {
|
|
|
|
return OBJECT_V0_ID(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ScummEngine_v0::actorToObj(int actor) {
|
|
|
|
return OBJECT_V0(actor, kObjectV0TypeActor);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScummEngine::objIsActor(int obj) {
|
|
|
|
return obj < _numActors;
|
2012-01-22 22:58:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int ScummEngine::objToActor(int obj) {
|
2012-02-10 22:58:59 +01:00
|
|
|
return obj;
|
2012-01-22 22:58:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int ScummEngine::actorToObj(int actor) {
|
2012-02-10 22:58:59 +01:00
|
|
|
return actor;
|
2012-01-22 22:58:10 +01:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::getObjX(int obj) {
|
2012-01-22 22:58:10 +01:00
|
|
|
if (obj < 1)
|
|
|
|
return 0; /* fix for indy4's map */
|
|
|
|
|
|
|
|
if (objIsActor(obj)) {
|
|
|
|
return derefActor(objToActor(obj), "getObjX")->getRealPos().x;
|
2001-10-16 10:01:48 +00:00
|
|
|
} else {
|
2002-04-11 17:19:16 +00:00
|
|
|
if (whereIsObject(obj) == WIO_NOT_FOUND)
|
2001-10-16 10:01:48 +00:00
|
|
|
return -1;
|
2002-07-16 18:51:27 +00:00
|
|
|
int x, y;
|
2017-11-30 20:09:24 -06:00
|
|
|
if (getObjectOrActorXY(obj, x, y) == -1)
|
|
|
|
return -1;
|
2002-07-16 18:51:27 +00:00
|
|
|
return x;
|
2001-10-16 10:01:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::getObjY(int obj) {
|
2012-01-22 22:58:10 +01:00
|
|
|
if (obj < 1)
|
|
|
|
return 0; /* fix for indy4's map */
|
|
|
|
|
|
|
|
if (objIsActor(obj)) {
|
|
|
|
return derefActor(objToActor(obj), "getObjY")->getRealPos().y;
|
2001-10-16 10:01:48 +00:00
|
|
|
} else {
|
2002-04-11 17:19:16 +00:00
|
|
|
if (whereIsObject(obj) == WIO_NOT_FOUND)
|
2001-10-16 10:01:48 +00:00
|
|
|
return -1;
|
2002-07-16 18:51:27 +00:00
|
|
|
int x, y;
|
2017-11-30 20:09:24 -06:00
|
|
|
if (getObjectOrActorXY(obj, x, y) == -1)
|
|
|
|
return -1;
|
2002-07-16 18:51:27 +00:00
|
|
|
return y;
|
2001-10-16 10:01:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::getObjOldDir(int obj) {
|
2003-03-08 00:56:43 +00:00
|
|
|
return newDirToOldDir(getObjNewDir(obj));
|
2001-10-16 10:01:48 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::getObjNewDir(int obj) {
|
2003-03-08 00:24:23 +00:00
|
|
|
int dir;
|
2012-01-22 22:58:10 +01:00
|
|
|
if (objIsActor(obj)) {
|
|
|
|
dir = derefActor(objToActor(obj), "getObjNewDir")->getFacing();
|
2001-12-27 17:51:58 +00:00
|
|
|
} else {
|
2003-03-08 00:24:23 +00:00
|
|
|
int x, y;
|
2002-07-16 18:51:27 +00:00
|
|
|
getObjectXYPos(obj, x, y, dir);
|
2001-12-27 17:51:58 +00:00
|
|
|
}
|
2003-03-08 00:24:23 +00:00
|
|
|
return dir;
|
2001-12-27 17:51:58 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
void ScummEngine::setObjectState(int obj, int state, int x, int y) {
|
2001-10-16 10:01:48 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
i = getObjectIndex(obj);
|
2002-04-11 17:19:16 +00:00
|
|
|
if (i == -1) {
|
2005-08-14 02:04:26 +00:00
|
|
|
debug(0, "setObjectState: no such object %d", obj);
|
2001-10-16 10:01:48 +00:00
|
|
|
return;
|
2001-11-26 19:57:57 +00:00
|
|
|
}
|
2001-10-16 10:01:48 +00:00
|
|
|
|
2005-04-01 09:55:17 +00:00
|
|
|
if (x != -1 && x != 0x7FFFFFFF) {
|
2003-11-16 20:52:57 +00:00
|
|
|
_objs[i].x_pos = x * 8;
|
|
|
|
_objs[i].y_pos = y * 8;
|
2001-10-16 10:01:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
addObjectToDrawQue(i);
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version >= 7) {
|
2005-04-01 09:55:17 +00:00
|
|
|
int imagecount;
|
|
|
|
if (state == 0xFF) {
|
|
|
|
state = getState(obj);
|
|
|
|
imagecount = getObjectImageCount(obj);
|
|
|
|
|
|
|
|
if (state < imagecount)
|
|
|
|
state++;
|
|
|
|
else
|
|
|
|
state = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state == 0xFE)
|
|
|
|
state = _rnd.getRandomNumber(getObjectImageCount(obj));
|
|
|
|
}
|
2001-10-16 10:01:48 +00:00
|
|
|
putState(obj, state);
|
|
|
|
}
|
|
|
|
|
2006-10-18 14:21:44 +00:00
|
|
|
int ScummEngine_v6::getDistanceBetween(bool is_obj_1, int b, int c, bool is_obj_2, int e, int f) {
|
2002-04-11 17:19:16 +00:00
|
|
|
int i, j;
|
|
|
|
int x, y;
|
|
|
|
int x2, y2;
|
|
|
|
|
2001-10-16 10:01:48 +00:00
|
|
|
j = i = 0xFF;
|
|
|
|
|
|
|
|
if (is_obj_1) {
|
2002-07-16 18:51:27 +00:00
|
|
|
if (getObjectOrActorXY(b, x, y) == -1)
|
2001-10-16 10:01:48 +00:00
|
|
|
return -1;
|
2003-05-13 23:42:41 +00:00
|
|
|
if (b < _numActors)
|
2005-06-17 17:11:30 +00:00
|
|
|
i = derefActor(b, "getDistanceBetween_is_obj_1")->_scalex;
|
2001-10-16 10:01:48 +00:00
|
|
|
} else {
|
|
|
|
x = b;
|
|
|
|
y = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_obj_2) {
|
2002-07-16 18:51:27 +00:00
|
|
|
if (getObjectOrActorXY(e, x2, y2) == -1)
|
2001-10-16 10:01:48 +00:00
|
|
|
return -1;
|
2003-05-13 23:42:41 +00:00
|
|
|
if (e < _numActors)
|
2005-06-17 17:11:30 +00:00
|
|
|
j = derefActor(e, "getDistanceBetween_is_obj_2")->_scalex;
|
2001-10-16 10:01:48 +00:00
|
|
|
} else {
|
|
|
|
x2 = e;
|
|
|
|
y2 = f;
|
|
|
|
}
|
|
|
|
|
2003-11-16 20:52:57 +00:00
|
|
|
return getDist(x, y, x2, y2) * 0xFF / ((i + j) / 2);
|
2001-10-16 10:01:48 +00:00
|
|
|
}
|
2001-11-06 20:00:47 +00:00
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
void ScummEngine::nukeFlObjects(int min, int max) {
|
2001-11-11 16:54:45 +00:00
|
|
|
ObjectData *od;
|
|
|
|
int i;
|
|
|
|
|
2005-08-14 02:04:26 +00:00
|
|
|
debug(0, "nukeFlObjects(%d,%d)", min, max);
|
2001-11-11 16:54:45 +00:00
|
|
|
|
2003-01-12 08:32:44 +00:00
|
|
|
for (i = (_numLocalObjects-1), od = _objs; --i >= 0; od++)
|
2002-04-11 17:19:16 +00:00
|
|
|
if (od->fl_object_index && od->obj_nr >= min && od->obj_nr <= max) {
|
2006-09-17 20:36:48 +00:00
|
|
|
_res->nukeResource(rtFlObject, od->fl_object_index);
|
2001-11-11 16:54:45 +00:00
|
|
|
od->obj_nr = 0;
|
|
|
|
od->fl_object_index = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-28 22:34:56 +00:00
|
|
|
void ScummEngine_v6::enqueueObject(int objectNumber, int objectX, int objectY, int objectWidth,
|
2003-11-08 21:59:32 +00:00
|
|
|
int objectHeight, int scaleX, int scaleY, int image, int mode) {
|
2002-04-21 21:20:32 +00:00
|
|
|
BlastObject *eo;
|
2001-11-11 16:54:45 +00:00
|
|
|
|
2003-05-15 17:57:52 +00:00
|
|
|
if (_blastObjectQueuePos >= (int)ARRAYSIZE(_blastObjectQueue)) {
|
2005-08-14 02:04:26 +00:00
|
|
|
error("enqueueObject: overflow");
|
2002-10-23 03:28:06 +00:00
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2003-05-15 17:57:52 +00:00
|
|
|
int idx = getObjectIndex(objectNumber);
|
2003-07-28 01:09:54 +00:00
|
|
|
assert(idx >= 0);
|
2001-11-11 16:54:45 +00:00
|
|
|
|
2003-01-16 00:40:19 +00:00
|
|
|
eo = &_blastObjectQueue[_blastObjectQueuePos++];
|
2002-04-22 13:55:28 +00:00
|
|
|
eo->number = objectNumber;
|
2004-10-07 16:34:54 +00:00
|
|
|
eo->rect.left = objectX;
|
2004-01-08 03:10:16 +00:00
|
|
|
eo->rect.top = objectY + _screenTop;
|
2002-04-21 21:20:32 +00:00
|
|
|
if (objectWidth == 0) {
|
2004-10-07 16:34:54 +00:00
|
|
|
eo->rect.right = eo->rect.left + _objs[idx].width;
|
2001-11-11 16:54:45 +00:00
|
|
|
} else {
|
2004-01-08 03:10:16 +00:00
|
|
|
eo->rect.right = eo->rect.left + objectWidth;
|
2001-11-11 16:54:45 +00:00
|
|
|
}
|
2002-04-21 21:20:32 +00:00
|
|
|
if (objectHeight == 0) {
|
2004-10-07 16:34:54 +00:00
|
|
|
eo->rect.bottom = eo->rect.top + _objs[idx].height;
|
2001-11-11 16:54:45 +00:00
|
|
|
} else {
|
2004-01-08 03:10:16 +00:00
|
|
|
eo->rect.bottom = eo->rect.top + objectHeight;
|
2001-11-11 16:54:45 +00:00
|
|
|
}
|
|
|
|
|
2002-11-06 15:29:49 +00:00
|
|
|
eo->scaleX = scaleX;
|
|
|
|
eo->scaleY = scaleY;
|
2002-04-22 13:55:28 +00:00
|
|
|
eo->image = image;
|
2002-04-24 04:26:09 +00:00
|
|
|
|
2002-04-21 21:20:32 +00:00
|
|
|
eo->mode = mode;
|
2001-11-11 16:54:45 +00:00
|
|
|
}
|
|
|
|
|
2005-04-28 22:34:56 +00:00
|
|
|
void ScummEngine_v6::drawBlastObjects() {
|
2002-04-21 21:20:32 +00:00
|
|
|
BlastObject *eo;
|
2001-11-11 16:54:45 +00:00
|
|
|
int i;
|
|
|
|
|
2003-01-16 00:40:19 +00:00
|
|
|
eo = _blastObjectQueue;
|
|
|
|
for (i = 0; i < _blastObjectQueuePos; i++, eo++) {
|
2002-04-21 21:20:32 +00:00
|
|
|
drawBlastObject(eo);
|
2001-11-11 16:54:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-28 22:34:56 +00:00
|
|
|
void ScummEngine_v6::drawBlastObject(BlastObject *eo) {
|
2001-11-11 16:54:45 +00:00
|
|
|
VirtScreen *vs;
|
2003-05-28 20:01:47 +00:00
|
|
|
const byte *bomp, *ptr;
|
2003-06-26 01:46:41 +00:00
|
|
|
int objnum;
|
2001-11-27 17:56:04 +00:00
|
|
|
BompDrawData bdd;
|
|
|
|
|
2007-09-08 11:15:27 +00:00
|
|
|
vs = &_virtscr[kMainVirtScreen];
|
2001-11-11 16:54:45 +00:00
|
|
|
|
2006-09-16 13:38:43 +00:00
|
|
|
assertRange(30, eo->number, _numGlobalObjects - 1, "blast object");
|
2002-04-22 13:55:28 +00:00
|
|
|
|
2003-01-01 11:25:04 +00:00
|
|
|
objnum = getObjectIndex(eo->number);
|
|
|
|
if (objnum == -1)
|
|
|
|
error("drawBlastObject: getObjectIndex on BlastObject %d failed", eo->number);
|
2002-04-22 13:55:28 +00:00
|
|
|
|
2005-06-23 14:10:52 +00:00
|
|
|
ptr = getOBIMFromObjectData(_objs[objnum]);
|
2002-07-07 20:25:23 +00:00
|
|
|
if (!ptr)
|
2003-06-26 01:46:41 +00:00
|
|
|
error("BlastObject object %d image not found", eo->number);
|
2002-04-11 17:19:16 +00:00
|
|
|
|
2003-06-26 01:46:41 +00:00
|
|
|
const byte *img = getObjectImage(ptr, eo->image);
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version == 8) {
|
2003-06-26 01:46:41 +00:00
|
|
|
assert(img);
|
|
|
|
bomp = img + 8;
|
2002-12-25 03:48:27 +00:00
|
|
|
} else {
|
|
|
|
if (!img)
|
2003-06-26 01:46:41 +00:00
|
|
|
img = getObjectImage(ptr, 1); // Backward compatibility with samnmax blast objects
|
|
|
|
assert(img);
|
2011-04-12 16:53:15 +02:00
|
|
|
bomp = findResourceData(MKTAG('B','O','M','P'), img);
|
2002-12-25 03:48:27 +00:00
|
|
|
}
|
2002-04-22 13:55:28 +00:00
|
|
|
|
2002-07-07 20:25:23 +00:00
|
|
|
if (!bomp)
|
|
|
|
error("object %d is not a blast object", eo->number);
|
2001-11-11 16:54:45 +00:00
|
|
|
|
2007-03-10 00:34:20 +00:00
|
|
|
bdd.dst = *vs;
|
2013-08-03 03:48:41 +02:00
|
|
|
bdd.dst.setPixels(vs->getPixels(0, 0));
|
2007-03-10 00:34:20 +00:00
|
|
|
bdd.x = eo->rect.left;
|
|
|
|
bdd.y = eo->rect.top;
|
|
|
|
|
|
|
|
// Skip the bomp header
|
|
|
|
if (_game.version == 8) {
|
|
|
|
bdd.src = bomp + 8;
|
|
|
|
} else {
|
|
|
|
bdd.src = bomp + 10;
|
|
|
|
}
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version == 8) {
|
2006-10-18 15:08:43 +00:00
|
|
|
bdd.srcwidth = READ_LE_UINT32(bomp);
|
|
|
|
bdd.srcheight = READ_LE_UINT32(bomp+4);
|
2002-12-25 03:48:27 +00:00
|
|
|
} else {
|
2006-10-18 15:08:43 +00:00
|
|
|
bdd.srcwidth = READ_LE_UINT16(bomp+2);
|
|
|
|
bdd.srcheight = READ_LE_UINT16(bomp+4);
|
2002-12-25 03:48:27 +00:00
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2002-11-06 07:28:39 +00:00
|
|
|
bdd.scale_x = (byte)eo->scaleX;
|
|
|
|
bdd.scale_y = (byte)eo->scaleY;
|
2007-03-10 00:34:20 +00:00
|
|
|
|
2021-11-13 23:40:38 +02:00
|
|
|
bdd.maskPtr = nullptr;
|
2007-03-10 00:34:20 +00:00
|
|
|
bdd.numStrips = _gdi->_numStrips;
|
2002-11-06 07:28:39 +00:00
|
|
|
|
|
|
|
if ((bdd.scale_x != 255) || (bdd.scale_y != 255)) {
|
2002-11-06 15:29:49 +00:00
|
|
|
bdd.shadowMode = 0;
|
2003-05-30 15:06:29 +00:00
|
|
|
} else {
|
2002-11-06 15:29:49 +00:00
|
|
|
bdd.shadowMode = eo->mode;
|
2002-11-06 07:28:39 +00:00
|
|
|
}
|
2007-03-10 00:34:20 +00:00
|
|
|
bdd.shadowPalette = _shadowPalette;
|
|
|
|
|
2021-11-13 23:40:38 +02:00
|
|
|
bdd.actorPalette = nullptr;
|
2007-03-10 00:34:20 +00:00
|
|
|
bdd.mirror = false;
|
|
|
|
|
|
|
|
drawBomp(bdd);
|
2002-11-06 07:28:39 +00:00
|
|
|
|
2004-01-08 03:24:41 +00:00
|
|
|
markRectAsDirty(vs->number, bdd.x, bdd.x + bdd.srcwidth, bdd.y, bdd.y + bdd.srcheight);
|
2001-11-11 16:54:45 +00:00
|
|
|
}
|
|
|
|
|
2005-04-28 22:34:56 +00:00
|
|
|
void ScummEngine_v6::removeBlastObjects() {
|
2022-07-24 22:39:29 +02:00
|
|
|
// While v6-7 games restore the rect immediately, we only reset
|
|
|
|
// the blastObject queue in here for v8, since their graphics
|
|
|
|
// has to remain on screen until after runAllScripts().
|
|
|
|
if (_game.version == 8) {
|
|
|
|
if (_blastObjectQueuePos != 0) {
|
|
|
|
for (int i = 0; i < _blastObjectQueuePos; i++) {
|
|
|
|
_blastObjectsRectsToBeRestored[i] = _blastObjectQueue[i].rect;
|
|
|
|
_blastObjectRectsQueue = _blastObjectQueuePos;
|
|
|
|
}
|
|
|
|
}
|
2001-11-11 16:54:45 +00:00
|
|
|
|
2022-07-24 22:39:29 +02:00
|
|
|
_blastObjectQueuePos = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < _blastObjectQueuePos; i++) {
|
|
|
|
restoreBlastObjectRect(_blastObjectQueue[i].rect);
|
2001-11-11 16:54:45 +00:00
|
|
|
}
|
2022-07-16 13:39:03 +02:00
|
|
|
|
2005-04-28 22:34:56 +00:00
|
|
|
_blastObjectQueuePos = 0;
|
2001-11-11 16:54:45 +00:00
|
|
|
}
|
|
|
|
|
2022-07-24 22:39:29 +02:00
|
|
|
void ScummEngine_v6::restoreBlastObjectsRects() {
|
|
|
|
// While v6-7 games restore the rect immediately in
|
|
|
|
// ScummEngine_v6::removeBlastObjects(), we do that here
|
|
|
|
// for v8, which has to restore the rects after runAllScripts().
|
|
|
|
if (_game.version < 8)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (int i = 0; i < _blastObjectRectsQueue; i++) {
|
|
|
|
restoreBlastObjectRect(_blastObjectsRectsToBeRestored[i]);
|
|
|
|
|
|
|
|
// Invalidate the rect after restoring it...
|
|
|
|
_blastObjectsRectsToBeRestored[i].setHeight(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
_blastObjectRectsQueue = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScummEngine_v6::restoreBlastObjectRect(Common::Rect r) {
|
2007-09-08 11:15:27 +00:00
|
|
|
VirtScreen *vs = &_virtscr[kMainVirtScreen];
|
2002-10-11 11:50:06 +00:00
|
|
|
|
|
|
|
int left_strip, right_strip;
|
|
|
|
int i;
|
|
|
|
|
2004-10-07 16:34:54 +00:00
|
|
|
r.clip(Common::Rect(vs->w, vs->h));
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2004-10-07 16:34:54 +00:00
|
|
|
if (r.width() <= 0 || r.height() <= 0)
|
2002-10-11 11:50:06 +00:00
|
|
|
return;
|
|
|
|
|
2004-01-08 03:10:16 +00:00
|
|
|
left_strip = r.left / 8;
|
2004-10-07 16:34:54 +00:00
|
|
|
right_strip = (r.right + (vs->xstart % 8)) / 8;
|
2002-10-11 11:50:06 +00:00
|
|
|
|
|
|
|
if (left_strip < 0)
|
|
|
|
left_strip = 0;
|
2006-09-17 20:22:47 +00:00
|
|
|
if (right_strip > _gdi->_numStrips - 1)
|
|
|
|
right_strip = _gdi->_numStrips - 1;
|
2002-10-11 11:50:06 +00:00
|
|
|
for (i = left_strip; i <= right_strip; i++)
|
2006-09-17 20:22:47 +00:00
|
|
|
_gdi->resetBackground(r.top, r.bottom, i);
|
2002-10-11 11:50:06 +00:00
|
|
|
|
2004-01-08 03:24:41 +00:00
|
|
|
markRectAsDirty(kMainVirtScreen, r, USAGE_BIT_RESTORED);
|
2001-11-11 16:54:45 +00:00
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::findLocalObjectSlot() {
|
2003-01-12 07:30:17 +00:00
|
|
|
int i;
|
|
|
|
|
2003-01-13 15:06:58 +00:00
|
|
|
for (i = 1; i < _numLocalObjects; i++) {
|
2003-12-21 13:44:23 +00:00
|
|
|
if (!_objs[i].obj_nr) {
|
|
|
|
memset(&_objs[i], 0, sizeof(_objs[i]));
|
2003-01-12 07:30:17 +00:00
|
|
|
return i;
|
2003-12-21 13:44:23 +00:00
|
|
|
}
|
2003-01-12 07:30:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
int ScummEngine::findFlObjectSlot() {
|
2001-11-26 19:57:57 +00:00
|
|
|
int i;
|
2003-12-26 23:11:35 +00:00
|
|
|
for (i = 1; i < _numFlObject; i++) {
|
2021-11-13 23:40:38 +02:00
|
|
|
if (_res->_types[rtFlObject][i]._address == nullptr)
|
2001-11-26 19:57:57 +00:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
error("findFlObjectSlot: Out of FLObject slots");
|
2002-05-05 18:10:29 +00:00
|
|
|
return -1;
|
2001-11-26 19:57:57 +00:00
|
|
|
}
|
|
|
|
|
2006-09-17 22:22:50 +00:00
|
|
|
void ScummEngine_v70he::loadFlObject(uint object, uint room) {
|
|
|
|
// Don't load an already stored object
|
|
|
|
for (int i = 0; i < _numStoredFlObjects; i++) {
|
|
|
|
if (_storedFlObjects[i].obj_nr == object)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScummEngine_v60he::loadFlObject(object, room);
|
|
|
|
}
|
|
|
|
|
2003-10-02 22:42:03 +00:00
|
|
|
void ScummEngine::loadFlObject(uint object, uint room) {
|
2001-11-26 19:57:57 +00:00
|
|
|
FindObjectInRoom foir;
|
2006-09-17 22:22:50 +00:00
|
|
|
int slot, objslot;
|
2001-11-26 19:57:57 +00:00
|
|
|
ObjectData *od;
|
2003-01-12 21:46:58 +00:00
|
|
|
byte *flob;
|
2001-11-26 19:57:57 +00:00
|
|
|
uint32 obcd_size, obim_size, flob_size;
|
2003-01-12 21:53:25 +00:00
|
|
|
bool isRoomLocked, isRoomScriptsLocked;
|
2001-11-26 19:57:57 +00:00
|
|
|
|
2002-12-27 14:36:28 +00:00
|
|
|
// Don't load an already loaded object
|
2005-10-14 08:39:27 +00:00
|
|
|
if (getObjectIndex(object) != -1)
|
2001-11-26 19:57:57 +00:00
|
|
|
return;
|
|
|
|
|
2002-12-27 14:36:28 +00:00
|
|
|
// Locate the object in the room resource
|
2001-11-26 19:57:57 +00:00
|
|
|
findObjectInRoom(&foir, foImageHeader | foCodeHeader, object, room);
|
|
|
|
|
2002-12-27 14:36:28 +00:00
|
|
|
// Add an entry for the new floating object in the local object table
|
2005-04-09 09:49:55 +00:00
|
|
|
objslot = findLocalObjectSlot();
|
|
|
|
if (objslot == -1)
|
2001-11-26 19:57:57 +00:00
|
|
|
error("loadFlObject: Local Object Table overflow");
|
2003-01-12 07:30:17 +00:00
|
|
|
|
|
|
|
od = &_objs[objslot];
|
2001-11-26 19:57:57 +00:00
|
|
|
|
2003-01-12 13:06:59 +00:00
|
|
|
// Dump object script
|
|
|
|
if (_dumpScripts) {
|
|
|
|
char buf[32];
|
2003-05-28 20:01:47 +00:00
|
|
|
const byte *ptr = foir.obcd;
|
2022-10-23 15:26:54 +02:00
|
|
|
Common::sprintf_s(buf, "roomobj-%u-", room);
|
2011-04-12 16:53:15 +02:00
|
|
|
ptr = findResource(MKTAG('V','E','R','B'), ptr);
|
2003-01-12 13:06:59 +00:00
|
|
|
dumpResource(buf, object, ptr);
|
|
|
|
}
|
|
|
|
|
2002-12-27 14:36:28 +00:00
|
|
|
// Setup sizes
|
2003-06-14 18:52:30 +00:00
|
|
|
obcd_size = READ_BE_UINT32(foir.obcd + 4);
|
2002-12-26 20:37:49 +00:00
|
|
|
od->OBCDoffset = 8;
|
|
|
|
od->OBIMoffset = obcd_size + 8;
|
2003-06-14 18:52:30 +00:00
|
|
|
obim_size = READ_BE_UINT32(foir.obim + 4);
|
2001-11-26 19:57:57 +00:00
|
|
|
flob_size = obcd_size + obim_size + 8;
|
|
|
|
|
2003-01-12 21:46:58 +00:00
|
|
|
// Lock room/roomScripts for the given room. They contains the OBCD/OBIM
|
|
|
|
// data, and a call to createResource might expire them, hence we lock them.
|
2006-09-17 20:36:48 +00:00
|
|
|
isRoomLocked = _res->isLocked(rtRoom, room);
|
|
|
|
isRoomScriptsLocked = _res->isLocked(rtRoomScripts, room);
|
2003-01-12 21:53:25 +00:00
|
|
|
if (!isRoomLocked)
|
2006-09-17 20:36:48 +00:00
|
|
|
_res->lock(rtRoom, room);
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version == 8 && !isRoomScriptsLocked)
|
2006-09-17 20:36:48 +00:00
|
|
|
_res->lock(rtRoomScripts, room);
|
2002-12-27 14:36:28 +00:00
|
|
|
|
|
|
|
// Allocate slot & memory for floating object
|
2001-11-26 19:57:57 +00:00
|
|
|
slot = findFlObjectSlot();
|
2006-09-17 20:36:48 +00:00
|
|
|
flob = _res->createResource(rtFlObject, slot, flob_size);
|
2002-12-27 14:36:28 +00:00
|
|
|
assert(flob);
|
|
|
|
|
|
|
|
// Copy object code + object image to floating object
|
2011-04-12 16:53:15 +02:00
|
|
|
WRITE_UINT32(flob, MKTAG('F','L','O','B'));
|
2009-07-01 20:51:34 +00:00
|
|
|
WRITE_BE_UINT32(flob + 4, flob_size);
|
2003-01-12 21:46:58 +00:00
|
|
|
memcpy(flob + 8, foir.obcd, obcd_size);
|
|
|
|
memcpy(flob + 8 + obcd_size, foir.obim, obim_size);
|
|
|
|
|
|
|
|
// Unlock room/roomScripts
|
2003-01-12 21:53:25 +00:00
|
|
|
if (!isRoomLocked)
|
2006-09-17 20:36:48 +00:00
|
|
|
_res->unlock(rtRoom, room);
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_game.version == 8 && !isRoomScriptsLocked)
|
2006-09-17 20:36:48 +00:00
|
|
|
_res->unlock(rtRoomScripts, room);
|
2001-11-26 19:57:57 +00:00
|
|
|
|
2002-12-27 14:36:28 +00:00
|
|
|
// Setup local object flags
|
2006-04-29 16:24:39 +00:00
|
|
|
resetRoomObject(od, flob, flob);
|
2001-11-26 19:57:57 +00:00
|
|
|
|
|
|
|
od->fl_object_index = slot;
|
|
|
|
}
|
2003-10-03 18:33:57 +00:00
|
|
|
|
|
|
|
} // End of namespace Scumm
|