TINSEL: Implement a container for accessing the INV_OBJECTs

This way we encapsulate the iteration, thus making sure that
the appropriate stride is used (Noir has more fields).
This commit is contained in:
Einar Johan Trøan Sømåen 2022-05-08 20:57:17 +02:00 committed by Filippos Karapetis
parent 83e62b6dd8
commit dd1ba7c85c
10 changed files with 280 additions and 152 deletions

View File

@ -743,7 +743,7 @@ enum {
/*-------------------------------------------------------------------------*/
static void InvTinselEvent(INV_OBJECT *pinvo, TINSEL_EVENT event, PLR_EVENT be, int index);
static void InvTinselEvent(const InventoryObject *pinvo, TINSEL_EVENT event, PLR_EVENT be, int index);
static void InvPdProcess(CORO_PARAM, const void *param);
Dialogs::Dialogs() {
@ -756,7 +756,6 @@ Dialogs::Dialogs() {
memset(_configStrings, 0, sizeof(_configStrings));
_invObjects = nullptr;
_numObjects = 0;
_invFilms = nullptr;
_noLanguage = false;
@ -843,6 +842,7 @@ Dialogs::Dialogs() {
}
Dialogs::~Dialogs() {
delete _invObjects;
if (_objArray[0] != NULL) {
DumpObjArray();
DumpDobjArray();
@ -1067,43 +1067,31 @@ void Dialogs::DumpObjArray() {
* Convert item ID number to pointer to item's compiled data
* i.e. Image data and Glitter code.
*/
INV_OBJECT *Dialogs::GetInvObject(int id) {
INV_OBJECT *pObject = _invObjects;
for (int i = 0; i < _numObjects; i++, pObject++) {
if (pObject->id == id)
return pObject;
const InventoryObject *Dialogs::GetInvObject(int id) {
auto object = _invObjects->GetInvObject(id);
if (!object) {
error("GetInvObject(%d): Trying to manipulate undefined inventory icon", id);
}
error("GetInvObject(%d): Trying to manipulate undefined inventory icon", id);
return object;
}
/**
* Returns true if the given id represents a valid inventory object
*/
bool Dialogs::GetIsInvObject(int id) {
INV_OBJECT *pObject = _invObjects;
for (int i = 0; i < _numObjects; i++, pObject++) {
if (pObject->id == id)
return true;
}
return false;
int index = _invObjects->GetObjectIndexIfExists(id);
return index != -1;
}
/**
* Convert item ID number to index.
*/
int Dialogs::GetObjectIndex(int id) {
INV_OBJECT *pObject = _invObjects;
for (int i = 0; i < _numObjects; i++, pObject++) {
if (pObject->id == id)
return i;
int index = _invObjects->GetObjectIndexIfExists(id);
if (index == -1) {
error("GetObjectIndex(%d): Trying to manipulate undefined inventory icon", id);
}
error("GetObjectIndex(%d): Trying to manipulate undefined inventory icon", id);
return index;
}
/**
@ -1156,9 +1144,9 @@ void Dialogs::InventoryIconCursor(bool bNewItem) {
int objIndex = GetObjectIndex(_heldItem);
if (TinselVersion == 3) {
INV_OBJECT *invObj = GetInvObject(_heldItem);
auto invObj = GetInvObject(_heldItem);
if (invObj->attribute & V3ATTR_X200) {
if (invObj->getAttribute() & V3ATTR_X200) {
_heldFilm = _vm->_systemReel->Get((SysReel)objIndex);
} else {
_heldFilm = _invFilms[objIndex];
@ -1169,8 +1157,8 @@ void Dialogs::InventoryIconCursor(bool bNewItem) {
}
_vm->_cursor->SetAuxCursor(_heldFilm);
} else {
INV_OBJECT *invObj = GetInvObject(_heldItem);
_vm->_cursor->SetAuxCursor(invObj->hIconFilm);
auto invObj = GetInvObject(_heldItem);
_vm->_cursor->SetAuxCursor(invObj->getIconFilm());
}
}
}
@ -1461,7 +1449,6 @@ void Dialogs::ClearInventory(int invno) {
void Dialogs::AddToInventory(int invno, int icon, bool hold) {
int i;
bool bOpen;
INV_OBJECT *invObj;
// Validate trying to add to a legal inventory
assert(invno == INV_1 || invno == INV_2 || invno == INV_3 || invno == INV_CONV || invno == INV_OPEN || (invno == INV_DEFAULT && TinselVersion >= 2));
@ -1477,10 +1464,10 @@ void Dialogs::AddToInventory(int invno, int icon, bool hold) {
bOpen = false;
if ((TinselVersion >= 2) && invno == INV_DEFAULT) {
invObj = GetInvObject(icon);
if (invObj->attribute & DEFINV2)
auto invObj = GetInvObject(icon);
if (invObj->getAttribute() & DEFINV2)
invno = INV_2;
else if (invObj->attribute & DEFINV1)
else if (invObj->getAttribute() & DEFINV1)
invno = INV_1;
else
invno = SysVar(SV_DEFAULT_INV);
@ -1507,8 +1494,8 @@ void Dialogs::AddToInventory(int invno, int icon, bool hold) {
// Count how many current contents have end attribute
for (i = 0, nei = 0; i < _invD[INV_CONV].NoofItems; i++) {
invObj = GetInvObject(_invD[INV_CONV].contents[i]);
if (invObj->attribute & CONVENDITEM)
auto invObj = GetInvObject(_invD[INV_CONV].contents[i]);
if (invObj->getAttribute() & CONVENDITEM)
nei++;
}
@ -1592,8 +1579,6 @@ bool Dialogs::RemFromInventory(int invno, int icon) {
* If the item is not already held, hold it.
*/
void Dialogs::HoldItem(int item, bool bKeepFilm) {
INV_OBJECT *invObj;
if (_heldItem != item) {
if ((TinselVersion >= 2) && (_heldItem != INV_NOICON)) {
// No longer holding previous item
@ -1602,14 +1587,14 @@ void Dialogs::HoldItem(int item, bool bKeepFilm) {
// If old held object is not in an inventory, and
// has a default, stick it in its default inventory.
if (!IsInInventory(_heldItem, INV_1) && !IsInInventory(_heldItem, INV_2)) {
invObj = GetInvObject(_heldItem);
auto invObj = GetInvObject(_heldItem);
if (invObj->attribute & DEFINV1)
if (invObj->getAttribute() & DEFINV1)
AddToInventory(INV_1, _heldItem);
else if (invObj->attribute & DEFINV2)
else if (invObj->getAttribute() & DEFINV2)
AddToInventory(INV_2, _heldItem);
else {
if ((TinselVersion < 3) || (!(invObj->attribute & V3ATTR_X200) && !(invObj->attribute & V3ATTR_X400))) {
if ((TinselVersion < 3) || (!(invObj->getAttribute() & V3ATTR_X200) && !(invObj->getAttribute() & V3ATTR_X400))) {
// Hook for definable default inventory
AddToInventory(INV_1, _heldItem);
}
@ -1621,8 +1606,8 @@ void Dialogs::HoldItem(int item, bool bKeepFilm) {
_vm->_cursor->DelAuxCursor(); // no longer aux cursor
if (item != INV_NOICON) {
invObj = GetInvObject(item);
_vm->_cursor->SetAuxCursor(invObj->hIconFilm); // and is aux. cursor
auto invObj = GetInvObject(item);
_vm->_cursor->SetAuxCursor(invObj->getIconFilm()); // and is aux. cursor
}
// WORKAROUND: If a held item is being removed that's not in either inventory (i.e. it was picked up
@ -2056,7 +2041,6 @@ void Dialogs::InvBoxes(bool InBody, int curX, int curY) {
*/
void Dialogs::InvLabels(bool InBody, int aniX, int aniY) {
int index; // Icon pointed to on this call
INV_OBJECT *invObj;
// Find out which icon is currently pointed to
if (!InBody)
@ -2077,8 +2061,8 @@ void Dialogs::InvLabels(bool InBody, int aniX, int aniY) {
_pointedIcon = INV_NOICON;
} else if (index != _pointedIcon) {
// A new icon is pointed to - run its script with POINTED event
invObj = GetInvObject(index);
if (invObj->hScript)
auto invObj = GetInvObject(index);
if (invObj->getScript())
InvTinselEvent(invObj, POINTED, PLR_NOEVENT, index);
_pointedIcon = index;
}
@ -2157,8 +2141,8 @@ void Dialogs::AdjustTop() {
* Insert an inventory icon object onto the display list.
*/
OBJECT *Dialogs::AddInvObject(int num, const FREEL **pfreel, const FILM **pfilm) {
INV_OBJECT *invObj = GetInvObject(num);
const FILM *pFilm = (const FILM *)_vm->_handle->LockMem(invObj->hIconFilm);
auto invObj = GetInvObject(num);
const FILM *pFilm = (const FILM *)_vm->_handle->LockMem(invObj->getIconFilm());
const FREEL *pfr = (const FREEL *)&pFilm->reels[0];
const MULTI_INIT *pmi = (MULTI_INIT *)_vm->_handle->LockMem(FROM_32(pfr->mobj));
OBJECT *pPlayObj; // The object we insert
@ -4556,8 +4540,6 @@ void Dialogs::InvPutDown(int index) {
}
void Dialogs::InvPickup(int index) {
INV_OBJECT *invObj;
// Do nothing if not clicked on anything
if (index == NOOBJECT)
return;
@ -4566,22 +4548,22 @@ void Dialogs::InvPickup(int index) {
if (_heldItem == INV_NOICON && _invD[_activeInv].contents[index] &&
((TinselVersion <= 1) || _invD[_activeInv].contents[index] != _heldItem)) {
// Pick-up
invObj = GetInvObject(_invD[_activeInv].contents[index]);
auto invObj = GetInvObject(_invD[_activeInv].contents[index]);
_thisIcon = _invD[_activeInv].contents[index];
if (TinselVersion >= 2)
InvTinselEvent(invObj, PICKUP, INV_PICKUP, index);
else if (invObj->hScript)
else if (invObj->getScript())
InvTinselEvent(invObj, WALKTO, INV_PICKUP, index);
} else if (_heldItem != INV_NOICON) {
// Put-down
invObj = GetInvObject(_heldItem);
auto invObj = GetInvObject(_heldItem);
// If DROPCODE set, send event, otherwise it's a putdown
if (invObj->attribute & IO_DROPCODE && invObj->hScript)
if (invObj->getAttribute() & IO_DROPCODE && invObj->getScript())
InvTinselEvent(invObj, PUTDOWN, INV_PICKUP, index);
else if (!(invObj->attribute & IO_ONLYINV1 && _activeInv != INV_1) && !(invObj->attribute & IO_ONLYINV2 && _activeInv != INV_2)) {
else if (!(invObj->getAttribute() & IO_ONLYINV1 && _activeInv != INV_1) && !(invObj->getAttribute() & IO_ONLYINV2 && _activeInv != INV_2)) {
if (TinselVersion >= 2)
InvPutDown(index);
else
@ -4679,7 +4661,7 @@ void Dialogs::InvWalkTo(const Common::Point &coOrds) {
void Dialogs::InvAction() {
int index;
INV_OBJECT *invObj;
const InventoryObject *invObj;
int aniX, aniY;
int i;
@ -4700,7 +4682,7 @@ void Dialogs::InvAction() {
invObj = GetInvObject(_invD[_activeInv].contents[index]);
if (TinselVersion >= 2)
_thisIcon = _invD[_activeInv].contents[index];
if ((TinselVersion >= 2) || (invObj->hScript))
if ((TinselVersion >= 2) || (invObj->getScript()))
InvTinselEvent(invObj, ACTION, INV_ACTION, index);
}
}
@ -4763,7 +4745,6 @@ void Dialogs::InvAction() {
void Dialogs::InvLook(const Common::Point &coOrds) {
int index;
INV_OBJECT *invObj;
Common::Point pt = coOrds;
switch (InvArea(pt.x, pt.y)) {
@ -4771,8 +4752,8 @@ void Dialogs::InvLook(const Common::Point &coOrds) {
index = InvItem(pt, false);
if (index != INV_NOICON) {
if (_invD[_activeInv].contents[index] && _invD[_activeInv].contents[index] != _heldItem) {
invObj = GetInvObject(_invD[_activeInv].contents[index]);
if (invObj->hScript)
auto invObj = GetInvObject(_invD[_activeInv].contents[index]);
if (invObj->getScript())
InvTinselEvent(invObj, LOOK, INV_LOOK, index);
}
}
@ -4939,10 +4920,7 @@ void Dialogs::EventToInventory(PLR_EVENT pEvent, const Common::Point &coOrds) {
* Changes (permanently) the animation film for that object.
*/
void Dialogs::SetObjectFilm(int object, SCNHANDLE hFilm) {
INV_OBJECT *invObj;
invObj = GetInvObject(object);
invObj->hIconFilm = hFilm;
_invObjects->SetObjectFilm(object, hFilm);
if (_heldItem != object)
_ItemsChanged = true;
@ -4978,7 +4956,7 @@ void Dialogs::syncInvInfo(Common::Serializer &s) {
}
if (TinselVersion >= 2) {
for (int i = 0; i < _numObjects; ++i)
for (int i = 0; i < _invObjects->numObjects(); ++i)
s.syncAsUint32LE(_invFilms[i]);
s.syncAsUint32LE(_heldFilm);
}
@ -4994,45 +4972,31 @@ void Dialogs::syncInvInfo(Common::Serializer &s) {
*/
// Note: the SCHANDLE type here has been changed to a void*
void Dialogs::RegisterIcons(void *cptr, int num) {
_numObjects = num;
_invObjects = (INV_OBJECT *)cptr;
if (TinselVersion == 0) {
// In Tinsel 0, the INV_OBJECT structure doesn't have an attributes field, so we
// need to 'unpack' the source structures into the standard Tinsel v1/v2 format
MEM_NODE *node = MemoryAllocFixed(_numObjects * sizeof(INV_OBJECT));
assert(node);
_invObjects = (INV_OBJECT *)MemoryDeref(node);
assert(_invObjects);
byte *srcP = (byte *)cptr;
INV_OBJECT *destP = _invObjects;
for (int i = 0; i < num; ++i, ++destP, srcP += 12) {
memmove(destP, srcP, 12);
destP->attribute = 0;
}
} else if (TinselVersion >= 2) {
int numObjects = num;
_invObjects = InstantiateInventoryObjects((const byte*)cptr, numObjects);
if (TinselVersion >= 2) {
if (_invFilms == NULL) {
// First time - allocate memory
MEM_NODE *node = MemoryAllocFixed(_numObjects * sizeof(SCNHANDLE));
MEM_NODE *node = MemoryAllocFixed(numObjects * sizeof(SCNHANDLE));
assert(node);
_invFilms = (SCNHANDLE *)MemoryDeref(node);
if (_invFilms == NULL)
error(NO_MEM, "inventory scripts");
memset(_invFilms, 0, _numObjects * sizeof(SCNHANDLE));
memset(_invFilms, 0, numObjects * sizeof(SCNHANDLE));
}
// Add defined permanent conversation icons
// and store all the films separately
int i;
INV_OBJECT *pio;
for (i = 0, pio = _invObjects; i < _numObjects; i++, pio++) {
if (pio->attribute & PERMACONV)
PermaConvIcon(pio->id, pio->attribute & CONVENDITEM);
for (int i = 0; i < numObjects; i++) {
auto pio = _invObjects->GetObjectByIndex(i);
if (pio->getAttribute() & PERMACONV)
PermaConvIcon(pio->getId(), pio->getAttribute() & CONVENDITEM);
_invFilms[i] = pio->hIconFilm;
_invFilms[i] = pio->getIconFilm();
}
}
}
/**
@ -5572,7 +5536,7 @@ extern void InventoryProcess(CORO_PARAM, const void *) {
/**************************************************************************/
struct OP_INIT {
INV_OBJECT *pinvo;
const InventoryObject *pinvo;
TINSEL_EVENT event;
PLR_EVENT bev;
int myEscape;
@ -5596,7 +5560,7 @@ static void ObjectProcess(CORO_PARAM, const void *param) {
if (TinselVersion <= 1)
CORO_INVOKE_1(AllowDclick, to->bev);
_ctx->pic = InitInterpretContext(GS_INVENTORY, to->pinvo->hScript, to->event, NOPOLY, 0, to->pinvo,
_ctx->pic = InitInterpretContext(GS_INVENTORY, to->pinvo->getScript(), to->event, NOPOLY, 0, to->pinvo,
to->myEscape);
CORO_INVOKE_1(Interpret, _ctx->pic);
@ -5606,7 +5570,7 @@ static void ObjectProcess(CORO_PARAM, const void *param) {
CORO_SLEEP(1);
int x, y;
_vm->_cursor->GetCursorXY(&x, &y, false);
if (_vm->_dialogs->InvItemId(x, y) != to->pinvo->id)
if (_vm->_dialogs->InvItemId(x, y) != to->pinvo->getId())
break;
// Fix the 'repeated pressing bug'
@ -5614,7 +5578,7 @@ static void ObjectProcess(CORO_PARAM, const void *param) {
CORO_KILL_SELF();
}
_ctx->pic = InitInterpretContext(GS_INVENTORY, to->pinvo->hScript, UNPOINT, NOPOLY, 0, to->pinvo);
_ctx->pic = InitInterpretContext(GS_INVENTORY, to->pinvo->getScript(), UNPOINT, NOPOLY, 0, to->pinvo);
CORO_INVOKE_1(Interpret, _ctx->pic);
}
@ -5624,10 +5588,10 @@ static void ObjectProcess(CORO_PARAM, const void *param) {
/**
* Run inventory item's Glitter code
*/
static void InvTinselEvent(INV_OBJECT *pinvo, TINSEL_EVENT event, PLR_EVENT be, int index) {
static void InvTinselEvent(const InventoryObject *pinvo, TINSEL_EVENT event, PLR_EVENT be, int index) {
OP_INIT to = {pinvo, event, be, 0};
if (_vm->_dialogs->InventoryIsHidden() || ((TinselVersion >= 2) && !pinvo->hScript))
if (_vm->_dialogs->InventoryIsHidden() || ((TinselVersion >= 2) && !pinvo->getScript()))
return;
_vm->_dialogs->_glitterIndex = index;
@ -5638,7 +5602,7 @@ extern void ObjectEvent(CORO_PARAM, int objId, TINSEL_EVENT event, bool bWait, i
// COROUTINE
CORO_BEGIN_CONTEXT;
Common::PROCESS *pProc;
INV_OBJECT *pInvo;
const InventoryObject *pInvo;
OP_INIT op;
CORO_END_CONTEXT(_ctx);
@ -5647,7 +5611,7 @@ extern void ObjectEvent(CORO_PARAM, int objId, TINSEL_EVENT event, bool bWait, i
if (result)
*result = false;
_ctx->pInvo = _vm->_dialogs->GetInvObject(objId);
if (!_ctx->pInvo->hScript)
if (!_ctx->pInvo->getScript())
return;
_ctx->op.pinvo = _ctx->pInvo;

View File

@ -26,6 +26,7 @@
#include "tinsel/dw.h"
#include "tinsel/events.h" // for PLR_EVENT, PLR_EVENT
#include "tinsel/inv_objects.h"
#include "tinsel/object.h"
#include "tinsel/movers.h"
@ -143,24 +144,6 @@ enum CONFTYPE {
TOP_WINDOW
};
/** structure of each inventory object */
struct INV_OBJECT {
int32 id; // inventory objects id
SCNHANDLE hIconFilm; // inventory objects animation film
SCNHANDLE hScript; // inventory objects event handling script
int32 attribute; // inventory object's attribute
// TODO: Commented out because there are variables
// with this struct type that are cast from memory blobs,
// so this breaks DW1 and DW2. We need to read these
// struct members individually instead of casting the blobs
// to this struct
// Noir
//int32 unknown;
//int32 title; // id of associated notebook title
};
struct INV_DEF {
int MinHicons; // }
int MinVicons; // } Dimension limits
@ -379,7 +362,7 @@ public:
void Select(int i, bool force);
void FillInInventory();
void InvCursor(InvCursorFN fn, int CurX, int CurY);
INV_OBJECT *GetInvObject(int id);
const InventoryObject *GetInvObject(int id);
bool UpdateString(const Common::KeyState &kbd);
bool InventoryIsActive() { return _inventoryState == ACTIVE_INV; }
bool IsMixingDeskControl() { return _invDragging == ID_MDCONT; }
@ -473,8 +456,7 @@ private:
INV_DEF _invD[MAX_NUM_INV]; // Conversation + 2 inventories + ...
int _activeInv; // Which inventory is currently active
INV_OBJECT *_invObjects; // Inventory objects' data
int _numObjects; // Number of inventory objects
InventoryObjects *_invObjects; // Inventory objects' data
SCNHANDLE *_invFilms;
DIRECTION _initialDirection;

View File

@ -0,0 +1,124 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "tinsel/inv_objects.h"
#include "common/memstream.h"
#include "tinsel/tinsel.h"
namespace Tinsel {
/** structure of each inventory object */
int32 InventoryObject::getUnknown() const {
error("Querying Noir-value from non-Noir game");
}
int32 InventoryObject::getTitle() const {
error("Querying Noir-value from non-Noir game");
}
class InventoryObjectT1 : public InventoryObject {
public:
InventoryObjectT1(Common::MemoryReadStreamEndian &stream) : InventoryObject(stream) {
_attribute = stream.readUint32();
}
// Tinsel1+
virtual int32 getAttribute() const {
return _attribute;
};
static const int SIZE = InventoryObject::SIZE + 4;
private:
int32 _attribute;
};
class InventoryObjectT3 : public InventoryObjectT1 {
public:
InventoryObjectT3(Common::MemoryReadStreamEndian &stream) : InventoryObjectT1(stream) {
_unknown = stream.readUint32();
_title = stream.readUint32();
}
// Noir:
virtual int32 getUnknown() const {
return _unknown;
}
virtual int32 getTitle() const {
return _title;
}
static const int SIZE = InventoryObjectT1::SIZE + 8;
private:
int32 _unknown;
int32 _title;
};
template<typename T>
class InventoryObjectsImpl : public InventoryObjects {
public:
InventoryObjectsImpl(const byte *objects, int numObjects) {
bool bigEndian = (TinselV1Mac || TinselV1Saturn);
auto stream = new Common::MemoryReadStreamEndian(objects, T::SIZE * numObjects, bigEndian, DisposeAfterUse::NO);
for (int i = 0; i < numObjects; i++) {
_objects.push_back(T(*stream));
}
assert((!stream->eos()) && stream->pos() == stream->size());
delete stream;
}
~InventoryObjectsImpl(){};
const InventoryObject *GetInvObject(int id) {
auto index = GetObjectIndexIfExists(id);
if (index != -1) {
return _objects.data() + index;
}
return nullptr;
}
const InventoryObject *GetObjectByIndex(int index) const {
assert(index >= 0 && index < numObjects());
return _objects.data() + index;
}
void SetObjectFilm(int id, SCNHANDLE hFilm) {
int index = GetObjectIndexIfExists(id);
_objects[index].setIconFilm(hFilm);
}
int GetObjectIndexIfExists(int id) const {
for (int i = 0; i < _objects.size(); i++) {
if (_objects[i].getId() == id) {
return i;
}
}
return -1;
};
int numObjects() const {
return _objects.size();
}
private:
Common::Array<T> _objects;
};
InventoryObjects *InstantiateInventoryObjects(const byte *invObjects, int numObjects) {
switch (TinselVersion) {
case 0:
return new InventoryObjectsImpl<InventoryObject>(invObjects, numObjects);
case 3:
return new InventoryObjectsImpl<InventoryObjectT3>(invObjects, numObjects);
default:
return new InventoryObjectsImpl<InventoryObjectT1>(invObjects, numObjects);
}
}
} // End of namespace Tinsel

View File

@ -0,0 +1,70 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TINSEL_INV_OBJECT_H
#define TINSEL_INV_OBJECT_H
#include "common/memstream.h"
#include "tinsel/dw.h"
namespace Tinsel {
class InventoryObject {
public:
InventoryObject(Common::MemoryReadStreamEndian &stream) {
_id = stream.readUint32();
_hIconFilm = stream.readUint32();
_hScript = stream.readUint32();
}
virtual ~InventoryObject() {}
int32 getId() const { return _id; }
SCNHANDLE getIconFilm() const { return _hIconFilm; };
void setIconFilm(SCNHANDLE hIconFilm) { _hIconFilm = hIconFilm; }
SCNHANDLE getScript() const { return _hScript; }
// Tinsel1+
virtual int32 getAttribute() const {
return 0;
};
// Noir:
virtual int32 getUnknown() const;
virtual int32 getTitle() const;
static const int SIZE = 12;
private:
int32 _id; // inventory objects id
SCNHANDLE _hIconFilm; // inventory objects animation film
SCNHANDLE _hScript; // inventory objects event handling script
};
class InventoryObjects {
public:
virtual ~InventoryObjects() {};
virtual const InventoryObject *GetInvObject(int id) = 0;
virtual const InventoryObject *GetObjectByIndex(int index) const = 0;
virtual void SetObjectFilm(int id, SCNHANDLE hFilm) = 0;
virtual int GetObjectIndexIfExists(int id) const = 0;
virtual int numObjects() const = 0;
};
InventoryObjects *InstantiateInventoryObjects(const byte *invObjects, int numObjects);
} // End of namespace Tinsel
#endif // TINSEL_INV_OBJECT_H

View File

@ -21,6 +21,7 @@ MODULE_OBJS := \
graphics.o \
handle.o \
heapmem.o \
inv_objects.o \
mareels.o \
metaengine.o \
move.o \

View File

@ -26,21 +26,19 @@
namespace Tinsel {
void Notebook::AddHyperlink(int32 id1, int32 id2) {
#if 0
INV_OBJECT *invObject = _vm->_dialogs->GetInvObject(id1);
auto *invObject = _vm->_dialogs->GetInvObject(id1);
if (invObject->title != 0) {
if (invObject->getTitle() != 0) {
error("A clue can only be hyperlinked if it only has one title!");
return;
}
invObject = _vm->_dialogs->GetInvObject(id2);
if (invObject->title != 0) {
if (invObject->getTitle() != 0) {
error("A clue can only be hyperlinked if it only has one title!");
return;
}
#endif
uint32 i;
for (i = 0; i < MAX_HYPERS; ++i) {

View File

@ -385,7 +385,7 @@ void FreeMasterInterpretContext() {
* @param pinvo Associated inventory object
*/
INT_CONTEXT *InitInterpretContext(GSORT gsort, SCNHANDLE hCode, TINSEL_EVENT event,
HPOLYGON hpoly, int actorid, INV_OBJECT *pinvo, int myEscape) {
HPOLYGON hpoly, int actorid, const InventoryObject *pinvo, int myEscape) {
INT_CONTEXT *ic;
ic = AllocateInterpretContext(gsort);

View File

@ -32,8 +32,7 @@ class Serializer;
namespace Tinsel {
// forward declaration
struct INV_OBJECT;
class InventoryObject;
enum RESUME_STATE {
RES_NOT, RES_1, RES_2, RES_SAVEGAME
@ -64,7 +63,7 @@ struct INT_CONTEXT {
TINSEL_EVENT event; ///< causal event
HPOLYGON hPoly; ///< associated polygon (if any)
int idActor; ///< associated actor (if any)
INV_OBJECT *pinvo; ///< associated inventory object
const InventoryObject *pinvo; ///< associated inventory object
// Previously local variables in Interpret()
int32 stack[PCODE_STACK_SIZE]; ///< interpeters run time stack
@ -99,7 +98,7 @@ INT_CONTEXT *InitInterpretContext(
TINSEL_EVENT event, // causal event
HPOLYGON hpoly, // associated polygon (if any)
int actorid, // associated actor (if any)
INV_OBJECT *pinvo,
const InventoryObject *pinvo,
int myEscape = -1); // associated inventory object
INT_CONTEXT *RestoreInterpretContext(INT_CONTEXT *ric);

View File

@ -1520,7 +1520,7 @@ void Offset(EXTREME extreme, int x, int y) {
/**
* OtherObject()
*/
int OtherObject(INV_OBJECT *pinvo) {
int OtherObject(const InventoryObject *pinvo) {
assert(pinvo != NULL);
// return held object or object clicked on - whichever is not the calling object
@ -1529,9 +1529,9 @@ int OtherObject(INV_OBJECT *pinvo) {
// WhichItemHeld() gives the held object
// GetIcon() gives the object clicked on
assert(_vm->_dialogs->GetIcon() == pinvo->id || _vm->_dialogs->WhichItemHeld() == pinvo->id);
assert(_vm->_dialogs->GetIcon() == pinvo->getId() || _vm->_dialogs->WhichItemHeld() == pinvo->getId());
if (_vm->_dialogs->GetIcon() == pinvo->id)
if (_vm->_dialogs->GetIcon() == pinvo->getId())
return _vm->_dialogs->WhichItemHeld();
else
return _vm->_dialogs->GetIcon();
@ -2101,13 +2101,13 @@ static void Print(CORO_PARAM, int x, int y, SCNHANDLE text, int time, bool bSust
}
static void PrintObjPointed(CORO_PARAM, const SCNHANDLE text, const INV_OBJECT *pinvo, OBJECT *&pText, const int textx, const int texty, const int item);
static void PrintObjPointed(CORO_PARAM, const SCNHANDLE text, const InventoryObject *pinvo, OBJECT *&pText, const int textx, const int texty, const int item);
static void PrintObjNonPointed(CORO_PARAM, const SCNHANDLE text, const OBJECT *pText);
/**
* Print the given inventory object's name or whatever.
*/
static void PrintObj(CORO_PARAM, const SCNHANDLE hText, const INV_OBJECT *pinvo, const int event, int myEscape) {
static void PrintObj(CORO_PARAM, const SCNHANDLE hText, const InventoryObject *pinvo, const int event, int myEscape) {
CORO_BEGIN_CONTEXT;
OBJECT *pText; // text object pointer
int textx, texty;
@ -2219,7 +2219,7 @@ static void PrintObj(CORO_PARAM, const SCNHANDLE hText, const INV_OBJECT *pinvo,
int x, y;
do {
// Give up if this item gets picked up
if (_vm->_dialogs->WhichItemHeld() == pinvo->id)
if (_vm->_dialogs->WhichItemHeld() == pinvo->getId())
break;
// Give way to non-POINTED-generated text
@ -2250,7 +2250,7 @@ static void PrintObj(CORO_PARAM, const SCNHANDLE hText, const INV_OBJECT *pinvo,
// Carry on until the cursor leaves this icon
_vm->_cursor->GetCursorXY(&x, &y, false);
} while (_vm->_dialogs->InvItemId(x, y) == pinvo->id);
} while (_vm->_dialogs->InvItemId(x, y) == pinvo->getId());
} else {
/*
* PrintObj() called from other event
@ -2324,7 +2324,7 @@ static void PrintObj(CORO_PARAM, const SCNHANDLE hText, const INV_OBJECT *pinvo,
CORO_END_CODE;
}
static void PrintObjPointed(CORO_PARAM, const SCNHANDLE text, const INV_OBJECT *pinvo, OBJECT *&pText, const int textx, const int texty, const int item) {
static void PrintObjPointed(CORO_PARAM, const SCNHANDLE text, const InventoryObject *pinvo, OBJECT *&pText, const int textx, const int texty, const int item) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@ -2334,7 +2334,7 @@ static void PrintObjPointed(CORO_PARAM, const SCNHANDLE text, const INV_OBJECT *
int x, y;
do {
// Give up if this item gets picked up
if (_vm->_dialogs->WhichItemHeld() == pinvo->id)
if (_vm->_dialogs->WhichItemHeld() == pinvo->getId())
break;
// Give way to non-POINTED-generated text
@ -2360,7 +2360,7 @@ static void PrintObjPointed(CORO_PARAM, const SCNHANDLE text, const INV_OBJECT *
// Carry on until the cursor leaves this icon
_vm->_cursor->GetCursorXY(&x, &y, false);
} while (_vm->_dialogs->InvItemId(x, y) == pinvo->id);
} while (_vm->_dialogs->InvItemId(x, y) == pinvo->getId());
CORO_END_CODE;
}
@ -3677,10 +3677,10 @@ static void TalkVia(int actor) {
/**
* ThisObject
*/
static int ThisObject(INV_OBJECT *pinvo) {
static int ThisObject(const InventoryObject *pinvo) {
assert(pinvo != NULL);
return pinvo->id;
return pinvo->getId();
}
/**

View File

@ -809,16 +809,6 @@ void LoadBasicChunks() {
RegisterGlobals(game.numGlobals);
cptr = FindChunk(INV_OBJ_SCNHANDLE, CHUNK_OBJECTS);
// Convert to native endianness
INV_OBJECT *io = (INV_OBJECT *)cptr;
for (int i = 0; i < game.numObjects; i++, io++) {
io->id = FROM_32(io->id);
io->hIconFilm = FROM_32(io->hIconFilm);
io->hScript = FROM_32(io->hScript);
io->attribute = FROM_32(io->attribute);
}
_vm->_dialogs->RegisterIcons(cptr, game.numObjects);
// Max polygons are 0 in the original DW1 V0 demo and in DW1 Mac (both in the demo and the full version)