[Scummvm-git-logs] scummvm master -> 757aea8ed64ff4131002916bb47aec062e7b3237
bluegr
noreply at scummvm.org
Wed May 11 05:59:12 UTC 2022
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
dd1ba7c85c TINSEL: Implement a container for accessing the INV_OBJECTs
1839780513 TINSEL: Convert inventory object attributes to enum class.
757aea8ed6 TINSEL: Implement basic menu support (NOIR)
Commit: dd1ba7c85c9867cba24c2c4efe4a0edbad5c1248
https://github.com/scummvm/scummvm/commit/dd1ba7c85c9867cba24c2c4efe4a0edbad5c1248
Author: Einar Johan Trøan SømaÌen (einarjohants at gmail.com)
Date: 2022-05-11T08:59:07+03:00
Commit Message:
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).
Changed paths:
A engines/tinsel/inv_objects.cpp
A engines/tinsel/inv_objects.h
engines/tinsel/dialogs.cpp
engines/tinsel/dialogs.h
engines/tinsel/module.mk
engines/tinsel/noir/notebook.cpp
engines/tinsel/pcode.cpp
engines/tinsel/pcode.h
engines/tinsel/tinlib.cpp
engines/tinsel/tinsel.cpp
diff --git a/engines/tinsel/dialogs.cpp b/engines/tinsel/dialogs.cpp
index 170af0f7f16..a2f84b2d046 100644
--- a/engines/tinsel/dialogs.cpp
+++ b/engines/tinsel/dialogs.cpp
@@ -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;
diff --git a/engines/tinsel/dialogs.h b/engines/tinsel/dialogs.h
index bcd71187fc0..ac6b93dc85a 100644
--- a/engines/tinsel/dialogs.h
+++ b/engines/tinsel/dialogs.h
@@ -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;
diff --git a/engines/tinsel/inv_objects.cpp b/engines/tinsel/inv_objects.cpp
new file mode 100644
index 00000000000..af0ba5f7c73
--- /dev/null
+++ b/engines/tinsel/inv_objects.cpp
@@ -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
diff --git a/engines/tinsel/inv_objects.h b/engines/tinsel/inv_objects.h
new file mode 100644
index 00000000000..a4bb84c8adf
--- /dev/null
+++ b/engines/tinsel/inv_objects.h
@@ -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
diff --git a/engines/tinsel/module.mk b/engines/tinsel/module.mk
index cfbe50200d9..7edd3eacb3d 100644
--- a/engines/tinsel/module.mk
+++ b/engines/tinsel/module.mk
@@ -21,6 +21,7 @@ MODULE_OBJS := \
graphics.o \
handle.o \
heapmem.o \
+ inv_objects.o \
mareels.o \
metaengine.o \
move.o \
diff --git a/engines/tinsel/noir/notebook.cpp b/engines/tinsel/noir/notebook.cpp
index 8a0d5879c85..b8022c0319d 100644
--- a/engines/tinsel/noir/notebook.cpp
+++ b/engines/tinsel/noir/notebook.cpp
@@ -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) {
diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp
index 49d7b992642..7b61f9ee520 100644
--- a/engines/tinsel/pcode.cpp
+++ b/engines/tinsel/pcode.cpp
@@ -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);
diff --git a/engines/tinsel/pcode.h b/engines/tinsel/pcode.h
index 519781c669d..4ecc9f12029 100644
--- a/engines/tinsel/pcode.h
+++ b/engines/tinsel/pcode.h
@@ -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);
diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp
index 5617adf151d..508f3b825f0 100644
--- a/engines/tinsel/tinlib.cpp
+++ b/engines/tinsel/tinlib.cpp
@@ -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();
}
/**
diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp
index 0fd70a370d3..13daadb9006 100644
--- a/engines/tinsel/tinsel.cpp
+++ b/engines/tinsel/tinsel.cpp
@@ -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)
Commit: 1839780513c05ad7b3e7cbc98a36e546021f8222
https://github.com/scummvm/scummvm/commit/1839780513c05ad7b3e7cbc98a36e546021f8222
Author: Einar Johan Trøan SømaÌen (einarjohants at gmail.com)
Date: 2022-05-11T08:59:07+03:00
Commit Message:
TINSEL: Convert inventory object attributes to enum class.
Changed paths:
engines/tinsel/dialogs.cpp
engines/tinsel/dialogs.h
engines/tinsel/inv_objects.cpp
engines/tinsel/inv_objects.h
diff --git a/engines/tinsel/dialogs.cpp b/engines/tinsel/dialogs.cpp
index a2f84b2d046..8875c3a24bf 100644
--- a/engines/tinsel/dialogs.cpp
+++ b/engines/tinsel/dialogs.cpp
@@ -72,13 +72,6 @@ namespace Tinsel {
#define INV_LOOK PLR_SRIGHT // for button events
#define INV_ACTION PLR_DLEFT //
-/** attribute values - may become bit field if further attributes are added */
-enum {
- IO_ONLYINV1 = 0x01,
- IO_ONLYINV2 = 0x02,
- IO_DROPCODE = 0x04
-};
-
//-----------------------
// Moveable window translucent rectangle position limits
enum {
@@ -1146,7 +1139,7 @@ void Dialogs::InventoryIconCursor(bool bNewItem) {
if (TinselVersion == 3) {
auto invObj = GetInvObject(_heldItem);
- if (invObj->getAttribute() & V3ATTR_X200) {
+ if (invObj->hasAttribute(InvObjAttr::V3ATTR_X200)) {
_heldFilm = _vm->_systemReel->Get((SysReel)objIndex);
} else {
_heldFilm = _invFilms[objIndex];
@@ -1465,9 +1458,9 @@ void Dialogs::AddToInventory(int invno, int icon, bool hold) {
if ((TinselVersion >= 2) && invno == INV_DEFAULT) {
auto invObj = GetInvObject(icon);
- if (invObj->getAttribute() & DEFINV2)
+ if (invObj->hasAttribute(InvObjAttr::DEFINV2))
invno = INV_2;
- else if (invObj->getAttribute() & DEFINV1)
+ else if (invObj->hasAttribute(InvObjAttr::DEFINV1))
invno = INV_1;
else
invno = SysVar(SV_DEFAULT_INV);
@@ -1495,7 +1488,7 @@ 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++) {
auto invObj = GetInvObject(_invD[INV_CONV].contents[i]);
- if (invObj->getAttribute() & CONVENDITEM)
+ if (invObj->hasAttribute(InvObjAttr::CONVENDITEM))
nei++;
}
@@ -1589,12 +1582,12 @@ void Dialogs::HoldItem(int item, bool bKeepFilm) {
if (!IsInInventory(_heldItem, INV_1) && !IsInInventory(_heldItem, INV_2)) {
auto invObj = GetInvObject(_heldItem);
- if (invObj->getAttribute() & DEFINV1)
+ if (invObj->hasAttribute(InvObjAttr::DEFINV1))
AddToInventory(INV_1, _heldItem);
- else if (invObj->getAttribute() & DEFINV2)
+ else if (invObj->hasAttribute(InvObjAttr::DEFINV2))
AddToInventory(INV_2, _heldItem);
else {
- if ((TinselVersion < 3) || (!(invObj->getAttribute() & V3ATTR_X200) && !(invObj->getAttribute() & V3ATTR_X400))) {
+ if ((TinselVersion < 3) || (!(invObj->hasAttribute(InvObjAttr::V3ATTR_X200)) && !(invObj->hasAttribute(InvObjAttr::V3ATTR_X400)))) {
// Hook for definable default inventory
AddToInventory(INV_1, _heldItem);
}
@@ -4560,10 +4553,10 @@ void Dialogs::InvPickup(int index) {
auto invObj = GetInvObject(_heldItem);
// If DROPCODE set, send event, otherwise it's a putdown
- if (invObj->getAttribute() & IO_DROPCODE && invObj->getScript())
+ if (invObj->hasAttribute(InvObjAttr::IO_DROPCODE) && invObj->getScript())
InvTinselEvent(invObj, PUTDOWN, INV_PICKUP, index);
- else if (!(invObj->getAttribute() & IO_ONLYINV1 && _activeInv != INV_1) && !(invObj->getAttribute() & IO_ONLYINV2 && _activeInv != INV_2)) {
+ else if (!(invObj->hasAttribute(InvObjAttr::IO_ONLYINV1) && _activeInv != INV_1) && !(invObj->hasAttribute(InvObjAttr::IO_ONLYINV2) && _activeInv != INV_2)) {
if (TinselVersion >= 2)
InvPutDown(index);
else
@@ -4989,8 +4982,8 @@ void Dialogs::RegisterIcons(void *cptr, int num) {
// and store all the films separately
for (int i = 0; i < numObjects; i++) {
auto pio = _invObjects->GetObjectByIndex(i);
- if (pio->getAttribute() & PERMACONV)
- PermaConvIcon(pio->getId(), pio->getAttribute() & CONVENDITEM);
+ if (pio->hasAttribute(InvObjAttr::PERMACONV))
+ PermaConvIcon(pio->getId(), pio->hasAttribute(InvObjAttr::CONVENDITEM));
_invFilms[i] = pio->getIconFilm();
}
diff --git a/engines/tinsel/dialogs.h b/engines/tinsel/dialogs.h
index ac6b93dc85a..808bb1a39d3 100644
--- a/engines/tinsel/dialogs.h
+++ b/engines/tinsel/dialogs.h
@@ -97,22 +97,6 @@ enum InventoryType { EMPTY,
enum InvCursorFN { IC_AREA,
IC_DROP };
-// attribute values - not a bit bit field to prevent portability problems
-#define DROPCODE 0x01
-#define ONLYINV1 0x02
-#define ONLYINV2 0x04
-#define DEFINV1 0x08
-#define DEFINV2 0x10
-#define PERMACONV 0x20
-#define CONVENDITEM 0x40
-// Noir only
-#define V3ATTR_X80 0x80
-#define V3ATTR_X200 0x200
-#define V3ATTR_X400 0x400
-#define NOTEBOOK_TITLE 0x800 // is a notebook title
-#define V3ATTR_X1000 0x1000
-#define V3ATTR_X2000 0x2000
-
#define sliderRange (_sliderYmax - _sliderYmin)
#define MAXSLIDES 4
#define MAX_PERMICONS 10 // Max permanent conversation icons
diff --git a/engines/tinsel/inv_objects.cpp b/engines/tinsel/inv_objects.cpp
index af0ba5f7c73..917dfc0ba81 100644
--- a/engines/tinsel/inv_objects.cpp
+++ b/engines/tinsel/inv_objects.cpp
@@ -25,7 +25,12 @@
namespace Tinsel {
-/** structure of each inventory object */
+InventoryObject::InventoryObject(Common::MemoryReadStreamEndian &stream) {
+ _id = stream.readUint32();
+ _hIconFilm = stream.readUint32();
+ _hScript = stream.readUint32();
+}
+
int32 InventoryObject::getUnknown() const {
error("Querying Noir-value from non-Noir game");
}
diff --git a/engines/tinsel/inv_objects.h b/engines/tinsel/inv_objects.h
index a4bb84c8adf..daa9fb5a45d 100644
--- a/engines/tinsel/inv_objects.h
+++ b/engines/tinsel/inv_objects.h
@@ -27,26 +27,46 @@
namespace Tinsel {
+// attribute values - not a bit bit field to prevent portability problems
+enum class InvObjAttr {
+ IO_DROPCODE = 0x01,
+ IO_ONLYINV1 = 0x02,
+ IO_ONLYINV2 = 0x04,
+ DEFINV1 = 0x08,
+ DEFINV2 = 0x10,
+ PERMACONV = 0x20,
+ CONVENDITEM = 0x40,
+
+ // Noir only
+ V3ATTR_X80 = 0x80,
+ V3ATTR_X200 = 0x200,
+ V3ATTR_X400 = 0x400,
+ NOTEBOOK_TITLE = 0x800, // is a notebook title
+ V3ATTR_X1000 = 0x1000,
+ V3ATTR_X2000 = 0x2000,
+};
+
class InventoryObject {
public:
- InventoryObject(Common::MemoryReadStreamEndian &stream) {
- _id = stream.readUint32();
- _hIconFilm = stream.readUint32();
- _hScript = stream.readUint32();
- }
+ InventoryObject(Common::MemoryReadStreamEndian &stream);
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;
- };
+ bool hasAttribute(InvObjAttr attribute) const {
+ return getAttribute() & (int32)attribute;
+ }
// Noir:
virtual int32 getUnknown() const;
virtual int32 getTitle() const;
static const int SIZE = 12;
+protected:
+ // Tinsel 1+
+ virtual int32 getAttribute() const {
+ return 0;
+ };
private:
int32 _id; // inventory objects id
SCNHANDLE _hIconFilm; // inventory objects animation film
Commit: 757aea8ed64ff4131002916bb47aec062e7b3237
https://github.com/scummvm/scummvm/commit/757aea8ed64ff4131002916bb47aec062e7b3237
Author: Einar Johan Trøan SømaÌen (einarjohants at gmail.com)
Date: 2022-05-11T08:59:07+03:00
Commit Message:
TINSEL: Implement basic menu support (NOIR)
Changed paths:
engines/tinsel/dialogs.cpp
engines/tinsel/dialogs.h
engines/tinsel/dw.h
engines/tinsel/multiobj.cpp
engines/tinsel/multiobj.h
engines/tinsel/noir/sysreel.h
diff --git a/engines/tinsel/dialogs.cpp b/engines/tinsel/dialogs.cpp
index 8875c3a24bf..54951a8ae61 100644
--- a/engines/tinsel/dialogs.cpp
+++ b/engines/tinsel/dialogs.cpp
@@ -158,6 +158,9 @@ enum PARTS_INDEX {
IX2_RIGHT1 = 40,
IX2_RIGHT2 = 41,
+ IX3_TICK = 27,
+ IX3_CROSS = 28,
+
T1_HOPEDFORREELS = 50,
T2_HOPEDFORREELS = 42
};
@@ -196,7 +199,7 @@ enum PARTS_INDEX {
#define ITEM_HEIGHT ((TinselVersion >= 2) ? 50 : 25) //
#define I_SEPARATION ((TinselVersion >= 2) ? 2 : 1) // Item separation
-#define NM_TOFF 11 // Title text Y offset from top
+#define NM_TOFF ((TinselVersion == 3) ? 21 : 11) // Title text Y offset from top
#define NM_TBT ((TinselVersion >= 2) ? 4 : 0) // Y, title box top
#define NM_TBB 33
#define NM_LSX ((TinselVersion >= 2) ? 4 : 0) // X, left side
@@ -331,6 +334,9 @@ struct CONFINIT {
#define BW 44 // Width of crosses and ticks etc. buttons
#define BH 41 // Height of crosses and ticks etc. buttons
+#define BW_T3 49
+#define BH_T3 45
+
/*-------------------------------------------------------------*\
| This is the main menu (that comes up when you hit F1 on a PC) |
\*-------------------------------------------------------------*/
@@ -349,10 +355,13 @@ struct CONFINIT {
#define BOXX 56 // X-position of text boxes
#define BOXY 50 // Y-position of text boxes
+#define T3_BOXX 60
+#define T3_BOXY 69
#define T2_OPTX 33
#define T2_OPTY 36
#define T2_BOX_V_SEP 12
#define T2_BOX_V2_SEP 6
+#define T3_BOX_V2_SEP 7
static CONFBOX t1OptionBox[] = {
@@ -387,8 +396,32 @@ static CONFBOX t2OptionBox[] = {
static CONFINIT t2ciOption = {6, 4, 144, 60, false, t2OptionBox, sizeof(t2OptionBox) / sizeof(CONFBOX), NO_HEADING};
-#define ciOption ((TinselVersion >= 2) ? t2ciOption : t1ciOption)
-#define optionBox ((TinselVersion >= 2) ? t2OptionBox : t1OptionBox)
+static CONFBOX t3OptionBox[] = {
+ {ARSBUT, OPENLOAD, TM_INDEX, NULL, SS_LOAD_OPTION, T2_OPTX, T2_OPTY, T2_EDIT_BOX1_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {ARSBUT, OPENSAVE, TM_INDEX, NULL, SS_SAVE_OPTION, T2_OPTX, T2_OPTY + (T2_BOX_HEIGHT + T2_BOX_V_SEP), T2_EDIT_BOX1_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {ARSBUT, OPENREST, TM_INDEX, NULL, SS_RESTART_OPTION, T2_OPTX, T2_OPTY + 2 * (T2_BOX_HEIGHT + T2_BOX_V_SEP), T2_EDIT_BOX1_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {ARSBUT, OPENSOUND, TM_INDEX, NULL, SS_SOUND_OPTION, T2_OPTX, T2_OPTY + 3 * (T2_BOX_HEIGHT + T2_BOX_V_SEP), T2_EDIT_BOX1_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {ARSBUT, OPENQUIT, TM_INDEX, NULL, SS_QUIT_OPTION, T2_OPTX, T2_OPTY + 4 * (T2_BOX_HEIGHT + T2_BOX_V_SEP), T2_EDIT_BOX1_WIDTH, T2_BOX_HEIGHT, NULL, 0}
+};
+
+static CONFINIT t3ciOption = {6, 4, 144, 60, false, t3OptionBox, sizeof(t3OptionBox) / sizeof(CONFBOX), NO_HEADING};
+
+static CONFINIT* ciOptionLookup[] = {
+ &t1ciOption,
+ &t1ciOption,
+ &t2ciOption,
+ &t3ciOption
+};
+
+static CONFBOX* ciOptionBoxLookup[] = {
+ t1OptionBox,
+ t1OptionBox,
+ t2OptionBox,
+ t3OptionBox
+};
+
+#define ciOption (*ciOptionLookup[TinselVersion])
+#define optionBox (ciOptionBoxLookup[TinselVersion])
/*-------------------------------------------------------------*\
| These are the load and save game menus. |
@@ -433,8 +466,22 @@ static CONFBOX t2LoadBox[] = {
{ARSGBUT, LOADGAME, TM_NONE, NULL, 0, 460, 100, BW, BH, NULL, IX2_TICK1},
{AAGBUT, CLOSEWIN, TM_NONE, NULL, 0, 460, 100 + 100, BW, BH, NULL, IX2_CROSS1}};
+static CONFBOX t3LoadBox[] = {
+ {RGROUP, LOADGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY, T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, LOADGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, LOADGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + 2 * (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, LOADGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + 3 * (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, LOADGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + 4 * (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, LOADGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + 5 * (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, LOADGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + 6 * (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, LOADGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + 7 * (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+
+ {AABUT, LOADGAME, TM_NONE, NULL, 0, 460, 100, BW, BH, NULL, IX2_TICK1},
+ {AATBUT, CLOSEWIN, TM_NONE, NULL, 0, 460, 100 + 100, BW, BH, NULL, IX2_CROSS1}};
+
static CONFINIT t1ciLoad = {10, 6, 20, 16, true, t1LoadBox, ARRAYSIZE(t1LoadBox), SIX_LOAD_HEADING};
static CONFINIT t2ciLoad = {10, 6, 40, 16, true, t2LoadBox, sizeof(t2LoadBox) / sizeof(CONFBOX), SS_LOAD_HEADING};
+static CONFINIT t3ciLoad = {10, 6, 40, 16, true, t3LoadBox, sizeof(t3LoadBox) / sizeof(CONFBOX), SS_LOAD_HEADING};
static CONFBOX t1SaveBox[NUM_RGROUP_BOXES + 2] = {
{RGROUP, SAVEGAME, TM_NONE, NULL, USE_POINTER, 28, SY, EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0},
@@ -465,13 +512,55 @@ static CONFBOX t2SaveBox[] = {
{ARSGBUT, SAVEGAME, TM_NONE, NULL, 0, 460, 100, BW, BH, NULL, IX2_TICK1},
{AAGBUT, CLOSEWIN, TM_NONE, NULL, 0, 460, 100 + 100, BW, BH, NULL, IX2_CROSS1}};
+static CONFBOX t3SaveBox[] = {
+ {RGROUP, SAVEGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY, T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, SAVEGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, SAVEGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + 2 * (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, SAVEGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + 3 * (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, SAVEGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + 4 * (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, SAVEGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + 5 * (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, SAVEGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + 6 * (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+ {RGROUP, SAVEGAME, TM_POINTER, NULL, 0, T3_BOXX, T3_BOXY + 7 * (T2_BOX_HEIGHT + T3_BOX_V2_SEP), T2_EDIT_BOX2_WIDTH, T2_BOX_HEIGHT, NULL, 0},
+
+ {AABUT, SAVEGAME, TM_NONE, NULL, 0, 460, 100, BW, BH, NULL, IX2_TICK1},
+ {AATBUT, CLOSEWIN, TM_NONE, NULL, 0, 460, 100 + 100, BW, BH, NULL, IX2_CROSS1}};
+
static CONFINIT t1ciSave = {10, 6, 20, 16, true, t1SaveBox, ARRAYSIZE(t1SaveBox), SIX_SAVE_HEADING};
static CONFINIT t2ciSave = {10, 6, 40, 16, true, t2SaveBox, sizeof(t2SaveBox) / sizeof(CONFBOX), SS_SAVE_HEADING};
+static CONFINIT t3ciSave = {10, 6, 40, 16, true, t3SaveBox, sizeof(t3SaveBox) / sizeof(CONFBOX), SS_SAVE_HEADING};
+
+static CONFINIT* ciLoadLookup[] = {
+ &t1ciLoad,
+ &t1ciLoad,
+ &t2ciLoad,
+ &t3ciLoad
+};
+
+static CONFBOX* ciLoadBoxLookup[] = {
+ t1LoadBox,
+ t1LoadBox,
+ t2LoadBox,
+ t3LoadBox
+};
+
+static CONFINIT* ciSaveLookup[] = {
+ &t1ciSave,
+ &t1ciSave,
+ &t2ciSave,
+ &t3ciSave
+};
+
+static CONFBOX* ciSaveBoxLookup[] = {
+ t1SaveBox,
+ t1SaveBox,
+ t2SaveBox,
+ t3SaveBox
+};
-#define ciLoad ((TinselVersion >= 2) ? t2ciLoad : t1ciLoad)
-#define loadBox ((TinselVersion >= 2) ? t2LoadBox : t1LoadBox)
-#define ciSave ((TinselVersion >= 2) ? t2ciSave : t1ciSave)
-#define saveBox ((TinselVersion >= 2) ? t2SaveBox : t1SaveBox)
+#define ciLoad (*ciLoadLookup[TinselVersion])
+#define loadBox (ciLoadBoxLookup[TinselVersion])
+#define ciSave (*ciSaveLookup[TinselVersion])
+#define saveBox (ciSaveBoxLookup[TinselVersion])
/*-------------------------------------------------------------*\
| This is the restart confirmation 'menu'. |
@@ -495,6 +584,10 @@ static CONFBOX t2RestartBox[] = {
{AAGBUT, INITGAME, TM_NONE, NULL, 0, 140, 78, BW, BH, NULL, IX2_TICK1},
{AAGBUT, CLOSEWIN, TM_NONE, NULL, 0, 60, 78, BW, BH, NULL, IX2_CROSS1}};
+static CONFBOX t3RestartBox[] = {
+ {AATBUT, INITGAME, TM_UNK4, NULL, 0, 140, 64, BW_T3, BH_T3, NULL, IX2_TICK1},
+ {AATBUT, CLOSEWIN, TM_UNK4, NULL, 0, 60, 64, BW_T3, BH_T3, NULL, IX2_CROSS1}};
+
#ifdef JAPAN
static CONFINIT t1ciRestart = {6, 2, 72, 53, false, t1RestartBox, ARRAYSIZE(t1RestartBox), SIX_RESTART_HEADING};
#else
@@ -502,8 +595,16 @@ static CONFINIT t1ciRestart = {4, 2, 98, 53, false, t1RestartBox, ARRAYSIZE(t1Re
#endif
static CONFINIT t1ciRestartPSX = {8, 2, 46, 53, false, t1RestartBoxPSX, ARRAYSIZE(t1RestartBoxPSX), SIX_RESTART_HEADING};
static CONFINIT t2ciRestart = {4, 2, 196, 53, false, t2RestartBox, sizeof(t2RestartBox) / sizeof(CONFBOX), SS_RESTART_HEADING};
+static CONFINIT t3ciRestart = {4, 2, 196, 53, false, t3RestartBox, sizeof(t3RestartBox) / sizeof(CONFBOX), SS_RESTART_HEADING};
+
+static CONFINIT* ciRestartLookup[] = {
+ &t1ciRestart,
+ &t1ciRestart,
+ &t2ciRestart,
+ &t3ciRestart
+};
-#define ciRestart ((TinselVersion >= 2) ? t2ciRestart : (TinselV1PSX ? t1ciRestartPSX : t1ciRestart))
+#define ciRestart (TinselV1PSX ? t1ciRestartPSX : *ciRestartLookup[TinselVersion])
/*-------------------------------------------------------------*\
| This is the sound control 'menu'. In Discworld 2, it also |
@@ -524,10 +625,27 @@ static CONFBOX t2SoundBox[] = {
{TOGGLE2, NOFUNC, TM_INDEX, NULL, SS_STITLE_TOGGLE, 100, 220, BW, BH, 0 /*&_vm->_config->_useSubtitles*/, 0},
{ROTATE, NOFUNC, TM_INDEX, NULL, SS_LANGUAGE_SELECT, 320, 220, BW, BH, NULL, 0}};
+static CONFBOX t3SoundBox[] = {
+ {ARSGBUT, MUSICVOL, TM_INDEX, NULL, SS_MVOL_SLIDER, 280, 50, 100, 2, /*&_vm->_config->_musicVolume*/ 0, 0},
+ {ARSGBUT, NOFUNC, TM_INDEX, NULL, SS_SVOL_SLIDER, 280, 50 + 30 * 1, 100, 2, /*&_vm->_config->_soundVolume*/ 0, 0},
+ {ARSGBUT, NOFUNC, TM_INDEX, NULL, SS_VVOL_SLIDER, 280, 50 + 30 * 2, 100, 2, /*&_vm->_config->_voiceVolume*/ 0, 0},
+ {ARSGBUT, NOFUNC, TM_INDEX, NULL, SS_TSPEED_SLIDER, 280, 160, 100, 2, /*&_vm->_config->_textSpeed*/ 0, 0},
+ {SLIDER, NOFUNC, TM_INDEX, NULL, SS_STITLE_TOGGLE, 100, 220, BW_T3, BH_T3, /*&_vm->_config->_useSubtitles*/ 0, 0}, // Should have type 7
+ {TOGGLE1, NOFUNC, TM_INDEX, NULL, SS_LANGUAGE_SELECT, 320, 220, BW_T3, BH_T3, NULL, 0}
+};
+
static CONFINIT t1ciSound = {10, 5, 20, 16, false, t1SoundBox, ARRAYSIZE(t1SoundBox), NO_HEADING};
static CONFINIT t2ciSound = {10, 5, 40, 16, false, t2SoundBox, sizeof(t2SoundBox) / sizeof(CONFBOX), SS_SOUND_HEADING};
+static CONFINIT t3ciSound = {10, 5, 40, 16, false, t3SoundBox, sizeof(t3SoundBox) / sizeof(CONFBOX), SS_SOUND_HEADING};
-#define ciSound ((TinselVersion >= 2) ? t2ciSound : t1ciSound)
+static CONFINIT* ciSoundLookup[] = {
+ &t1ciSound,
+ &t1ciSound,
+ &t2ciSound,
+ &t3ciSound
+};
+
+#define ciSound (*ciSoundLookup[TinselVersion])
/*-------------------------------------------------------------*\
| This is the (mouse) control 'menu'. |
@@ -610,11 +728,22 @@ static CONFBOX t2QuitBox[] = {
{AAGBUT, IQUITGAME, TM_NONE, NULL, 0, 140, 78, BW, BH, NULL, IX2_TICK1},
{AAGBUT, CLOSEWIN, TM_NONE, NULL, 0, 60, 78, BW, BH, NULL, IX2_CROSS1}};
+static CONFBOX t3QuitBox[] = {
+ {AATBUT, IQUITGAME, TM_NONE, NULL, 0, 140, 64, BW_T3, BH_T3, NULL, IX3_CROSS},
+ {AATBUT, CLOSEWIN, TM_NONE, NULL, 0, 60, 64, BW_T3, BH_T3, NULL, IX3_TICK}};
+
static CONFINIT t1ciQuit = {4, 2, 98, 53, false, t1QuitBox, ARRAYSIZE(t1QuitBox), SIX_QUIT_HEADING};
static CONFINIT t2ciQuit = {4, 2, 196, 53, false, t2QuitBox, sizeof(t2QuitBox) / sizeof(CONFBOX), SS_QUIT_HEADING};
+static CONFINIT t3ciQuit = {4, 2, 196, 53, false, t3QuitBox, sizeof(t3QuitBox) / sizeof(CONFBOX), SS_QUIT_HEADING};
-#define quitBox ((TinselVersion >= 2) ? t2QuitBox : t1QuitBox)
-#define ciQuit ((TinselVersion >= 2) ? t2ciQuit : t1ciQuit)
+static CONFINIT* ciQuitLookup[] = {
+ &t1ciQuit,
+ &t1ciQuit,
+ &t2ciQuit,
+ &t3ciQuit
+};
+
+#define ciQuit (*ciQuitLookup[TinselVersion])
/***************************************************************************\
|************************ Startup and shutdown ***********************|
@@ -2201,23 +2330,26 @@ enum { FROM_HANDLE,
* Set up a rectangle as the background to the inventory window.
* Additionally, sticks the window title up.
*/
-void Dialogs::AddBackground(OBJECT **rect, OBJECT **title, int extraH, int extraV, int textFrom) {
+void Dialogs::AddBackground(OBJECT **rect, const Common::Rect &bounds, OBJECT **title, int textFrom) {
// Why not 2 ????
- int width = _TLwidth + extraH + _TRwidth + NM_BG_SIZ_X;
- int height = _TLheight + extraV + _BLheight + NM_BG_SIZ_Y;
+ int width = bounds.width();
+ int height = bounds.height();
// Create a rectangle object
_rectObject = *rect = TranslucentObject(width, height);
// add it to display list and position it
MultiInsertObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), *rect);
- MultiSetAniXYZ(*rect, _invD[_activeInv].inventoryX + NM_BG_POS_X,
- _invD[_activeInv].inventoryY + NM_BG_POS_Y,
- Z_INV_BRECT);
+ PositionInventory(*rect,
+ (TinselVersion < 3 ? NM_BG_POS_X : 0),
+ (TinselVersion < 3 ? NM_BG_POS_Y : 0),
+ Z_INV_BRECT);
if (title == NULL)
return;
+ assert(TinselVersion < 3);
+
// Create text object using title string
if (textFrom == FROM_HANDLE) {
LoadStringRes(_invD[_activeInv].hInvTitle, _vm->_font->TextBufferAddr(), TBUFSZ);
@@ -2236,13 +2368,6 @@ void Dialogs::AddBackground(OBJECT **rect, OBJECT **title, int extraH, int extra
}
}
-/**
- * Set up a rectangle as the background to the inventory window.
- */
-void Dialogs::AddBackground(OBJECT **rect, int extraH, int extraV) {
- AddBackground(rect, NULL, extraH, extraV, 0);
-}
-
Common::Rect MultiBounds(OBJECT *obj) {
Common::Rect bounds;
bounds.left = MultiLeftmost(obj);
@@ -2255,15 +2380,14 @@ Common::Rect MultiBounds(OBJECT *obj) {
/**
* Adds a title for a dialog
*/
-void Dialogs::AddTitle(OBJECT **title, int extraH) {
- int width = _TLwidth + extraH + _TRwidth + NM_BG_SIZ_X;
-
- // Create text object using title string
+void Dialogs::AddTitle(OBJECT **title, const Common::Rect &bounds) {
if (_invD[_activeInv].hInvTitle != (SCNHANDLE)NO_HEADING) {
LoadStringRes(_invD[_activeInv].hInvTitle, _vm->_font->TextBufferAddr(), TBUFSZ);
+
+ int xOffset = (TinselVersion == 3) ? 0 : NM_BG_POS_X;
*title = ObjectTextOut(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _vm->_font->TextBufferAddr(), 0,
- _invD[_activeInv].inventoryX + (width / 2) + NM_BG_POS_X, _invD[_activeInv].inventoryY + NM_TOFF,
- _vm->_font->GetTagFontHandle(), TXT_CENTER, 0);
+ _invD[_activeInv].inventoryX + (bounds.width() / 2) + xOffset, _invD[_activeInv].inventoryY + NM_TOFF,
+ _vm->_font->GetTagFontHandle(), TXT_CENTER, 0);
assert(*title);
MultiSetZPosition(*title, Z_INV_HTEXT);
}
@@ -2658,6 +2782,87 @@ int Dialogs::AddExtraWindow(int x, int y, OBJECT **retObj) {
return n;
}
+void Dialogs::ConstructInventoryCommon(SysReel reel, bool hasTitle) {
+ DumpObjArray();
+
+ // Get the frame's data
+ _objArray[0] = InsertSystemReelObj(reel);
+
+ // Center the inventory.
+ auto bounds = MultiBounds(_objArray[0]);
+ _invD[_activeInv].inventoryX = (SCREEN_WIDTH - bounds.width()) / 2;
+ _invD[_activeInv].inventoryY = (SCREEN_HEIGHT - bounds.height()) / 2;
+ PositionInventory(_objArray[0], 0, 0, Z_INV_MFRAME);
+ MultiSetZPosition(_objArray[0], 16);
+
+ AddBackground(&_objArray[1], bounds);
+ if (hasTitle) {
+ AddTitle(&_objArray[2], bounds);
+ if (_objArray[2]) {
+ // We currently skip this, as AddTitle still needs ObjTextOut updates.
+ warning("TODO: Align title");
+ }
+ }
+}
+
+void Dialogs::ConstructMainInventory() {
+ warning("TODO: Complete implementation of ConstructMainInventory");
+ ConstructInventoryCommon(SysReel::INVMAIN, false);
+ _invD[_activeInv].FirstDisp = 0;
+
+ // TODO: Slider, Scrolling
+
+ FillInInventory();
+}
+
+void Dialogs::PositionInventory(OBJECT *pMultiObj, int xOffset, int yOffset, int zPosition) {
+ MultiSetAniXYZ(pMultiObj, _invD[_activeInv].inventoryX + xOffset, _invD[_activeInv].inventoryY + yOffset, zPosition);
+}
+
+SysReel GetSysReelForMenu(int menuId) {
+ switch(menuId) {
+ case MAIN_MENU:
+ return SysReel::OPTIONS_MENU;
+ break;
+ case LOAD_MENU:
+ case SAVE_MENU:
+ return SysReel::LOADSAVE_MENU;
+ break;
+ case QUIT_MENU:
+ return SysReel::QUIT_MENU;
+ break;
+ case SOUND_MENU:
+ return SysReel::SUBTITLES_MENU;
+ break;
+ default:
+ error("Unknown menu: %d", menuId);
+ }
+}
+
+void Dialogs::ConstructConversationInventory() {
+ warning("TODO: Complete implementation of ConstructConversationInventory");
+ ConstructInventoryCommon(SysReel::CONVERSATION_FRAME, true);
+}
+
+void Dialogs::ConstructOtherInventory(int menuId) {
+ warning("TODO: Complete implementation of ConstructOtherInventory");
+ SysReel reel = GetSysReelForMenu(menuId);
+ ConstructInventoryCommon(reel, true);
+
+ if (cd.bExtraWin) {
+ warning("TODO: Complete scrollbar implementation");
+ SCNHANDLE sliderReel = _vm->_systemReel->Get(SysReel::SLIDER);
+ const FILM *pfilm = (const FILM *)_vm->_handle->LockMem(sliderReel);
+ _objArray[3] = _slideObject = InsertReelObj(pfilm->reels);
+ MultiSetAniXYZ(_slideObject,
+ _invD[_activeInv].inventoryX + 420,
+ _sliderYpos,
+ Z_INV_MFRAME - 1);
+ }
+ AddBoxes(true);
+
+}
+
/**
* Construct an inventory window - either a standard one, with
* background, slider and icons, or a re-sizing window.
@@ -2682,10 +2887,7 @@ void Dialogs::ConstructInventory(InventoryType filling) {
// Dispose of anything it may be replacing
for (int i = 0; i < MAX_WCOMP; i++) {
- if (retObj[i] != NULL) {
- MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), retObj[i]);
- retObj[i] = nullptr;
- }
+ MultiDeleteObjectIfExists(FIELD_STATUS, &retObj[i]);
}
// Get the frame's data
@@ -2831,10 +3033,13 @@ void Dialogs::ConstructInventory(InventoryType filling) {
OBJECT **rect, **title;
+ Common::Rect bounds;
+ bounds.right = _TLwidth + eH + _TRwidth + NM_BG_SIZ_X;
+ bounds.bottom = _TLheight + eV + _BLheight + NM_BG_SIZ_Y;
// Draw background, slider and icons
if ((TinselVersion >= 2) && (filling != EMPTY)) {
- AddBackground(&retObj[n++], eH, eV);
- AddTitle(&retObj[n++], eH);
+ AddBackground(&retObj[n++], bounds);
+ AddTitle(&retObj[n++], bounds);
}
if (filling == FULL) {
@@ -2842,7 +3047,7 @@ void Dialogs::ConstructInventory(InventoryType filling) {
rect = &retObj[n++];
title = &retObj[n++];
- AddBackground(rect, title, eH, eV, FROM_HANDLE);
+ AddBackground(rect, bounds, title, FROM_HANDLE);
}
if (_activeInv == INV_CONV) {
@@ -2868,7 +3073,7 @@ void Dialogs::ConstructInventory(InventoryType filling) {
rect = &retObj[n++];
title = &retObj[n++];
- AddBackground(rect, title, eH, eV, FROM_STRING);
+ AddBackground(rect, bounds, title, FROM_STRING);
if (cd.bExtraWin)
n += AddExtraWindow(invX, invY, &retObj[n]);
} else {
@@ -3341,7 +3546,7 @@ bool Dialogs::ConvIsHidden() {
/**
* Start up an inventory window.
*/
-void Dialogs::PopUpInventory(int invno) {
+void Dialogs::PopUpInventory(int invno, int menuId) {
assert(invno == INV_1 || invno == INV_2 || invno == INV_CONV || invno == INV_CONF || invno == INV_MENU); // Trying to open illegal inventory
if (_inventoryState == IDLE_INV) {
@@ -3376,17 +3581,36 @@ void Dialogs::PopUpInventory(int invno) {
_inventoryState = ACTIVE_INV; // Inventory actiive
_InventoryHidden = false; // Not hidden
_InventoryMaximised = _invD[_activeInv].bMax;
- if (invno != INV_CONF) // Configuration window?
- ConstructInventory(FULL); // Draw it up
- else {
- ConstructInventory(CONF); // Draw it up
+ if (TinselVersion == 3) {
+ switch (invno) {
+ case INV_CONV:
+ ConstructConversationInventory();
+ break;
+ case INV_1:
+ case INV_2:
+ case INV_3:
+ case INV_4:
+ ConstructMainInventory();
+ break;
+ default: // Should be menu.
+ ConstructOtherInventory(menuId);
+ break;
+ }
+ } else {
+ if (invno != INV_CONF) // Configuration window?
+ ConstructInventory(FULL); // Draw it up
+ else {
+ ConstructInventory(CONF); // Draw it up
+ }
}
}
}
void Dialogs::SetMenuGlobals(CONFINIT *ci) {
- _invD[INV_CONF].MinHicons = _invD[INV_CONF].MaxHicons = _invD[INV_CONF].NoofHicons = ci->h;
- _invD[INV_CONF].MaxVicons = _invD[INV_CONF].MinVicons = _invD[INV_CONF].NoofVicons = ci->v;
+ if (TinselVersion < 3) {
+ _invD[INV_CONF].MinHicons = _invD[INV_CONF].MaxHicons = _invD[INV_CONF].NoofHicons = ci->h;
+ _invD[INV_CONF].MaxVicons = _invD[INV_CONF].MinVicons = _invD[INV_CONF].NoofVicons = ci->v;
+ }
_invD[INV_CONF].inventoryX = ci->x;
_invD[INV_CONF].inventoryY = ci->y;
cd.bExtraWin = ci->bExtraWin;
@@ -3454,7 +3678,13 @@ void Dialogs::OpenMenu(CONFTYPE menuType) {
_displayedLanguage = TextLanguage();
#if 1
// FIXME: Hack to setup CONFBOX pointer to data in the global Config object
- if (TinselVersion >= 2) {
+ if (TinselVersion == 3) {
+ t3SoundBox[0].ival = &_vm->_config->_musicVolume;
+ t3SoundBox[1].ival = &_vm->_config->_soundVolume;
+ t3SoundBox[2].ival = &_vm->_config->_voiceVolume;
+ t3SoundBox[3].ival = &_vm->_config->_textSpeed;
+ t3SoundBox[4].ival = &_vm->_config->_useSubtitles;
+ } else if (TinselVersion >= 2) {
t2SoundBox[0].ival = &_vm->_config->_musicVolume;
t2SoundBox[1].ival = &_vm->_config->_soundVolume;
t2SoundBox[2].ival = &_vm->_config->_voiceVolume;
@@ -3550,7 +3780,7 @@ void Dialogs::OpenMenu(CONFTYPE menuType) {
if (_heldItem != INV_NOICON)
_vm->_cursor->DelAuxCursor(); // no longer aux cursor
- PopUpInventory(INV_CONF);
+ PopUpInventory(INV_CONF, menuType);
// Make initial box selections if appropriate
if (menuType == SAVE_MENU || menuType == LOAD_MENU || menuType == HOPPER_MENU1 || menuType == HOPPER_MENU2)
diff --git a/engines/tinsel/dialogs.h b/engines/tinsel/dialogs.h
index 808bb1a39d3..9bba1f88786 100644
--- a/engines/tinsel/dialogs.h
+++ b/engines/tinsel/dialogs.h
@@ -47,7 +47,7 @@ enum {
INV_CONV = 0,
INV_1 = 1,
INV_2 = 2,
- INV_CONF = 3,
+ DW0_INV_CONF = 3,
INV_MENU = 3, // DW2 constant
NUM_INV_V0 = 4,
@@ -58,7 +58,8 @@ enum {
// Noir constants
INV_3 = 3,
INV_4 = 4,
- NUM_INV_V3 = 5,
+ NOIR_INV_CONF = 5,
+ NUM_INV_V3 = 6,
INV_7NOINV = 7,
INV_8NOINV = 8,
INV_NOTEBOOK = 9,
@@ -66,6 +67,7 @@ enum {
MAX_NUM_INV = NUM_INV_V3 // For determination of _invD array size
};
+#define INV_CONF ((TinselVersion == 3) ? NOIR_INV_CONF : DW0_INV_CONF)
#define NUM_INV ((TinselVersion == 3) ? NUM_INV_V3 : NUM_INV_V0)
enum {
@@ -226,6 +228,7 @@ enum BFUNC {
enum TM { TM_POINTER,
TM_INDEX,
TM_STRINGNUM,
+ TM_UNK4,
TM_NONE };
// For SlideSlider() and similar
@@ -259,12 +262,14 @@ struct BUTTONEFFECT {
bool press; // true = button press; false = button toggle
};
+enum class SysReel;
+
class Dialogs {
public:
Dialogs();
virtual ~Dialogs();
- void PopUpInventory(int invno);
+ void PopUpInventory(int invno, int menuId = -1);
void OpenMenu(CONFTYPE type);
void Xmovement(int x);
@@ -394,14 +399,18 @@ private:
void InvLabels(bool InBody, int aniX, int aniY);
void AdjustTop();
OBJECT *AddInvObject(int num, const FREEL **pfreel, const FILM **pfilm);
- void AddBackground(OBJECT **rect, OBJECT **title, int extraH, int extraV, int textFrom);
- void AddBackground(OBJECT **rect, int extraH, int extraV);
- void AddTitle(OBJECT **title, int extraH);
+ void AddBackground(OBJECT **rect, const Common::Rect &bounds, OBJECT **title = nullptr, int textFrom = 0);
+ void AddTitle(OBJECT **title, const Common::Rect &rect);
void AddSlider(OBJECT **slide, const FILM *pfilm);
void AddBox(int *pi, const int i);
void AddEWSlider(OBJECT **slide, const FILM *pfilm);
+ void PositionInventory(OBJECT *pMultiObj, int xOffset, int yOffset, int zPosition);
int AddExtraWindow(int x, int y, OBJECT **retObj);
+ void ConstructInventoryCommon(SysReel reel, bool hasTitle);
+ void ConstructConversationInventory();
void ConstructInventory(InventoryType filling);
+ void ConstructOtherInventory(int menuId);
+ void ConstructMainInventory();
void AlterCursor(int num);
void SetMenuGlobals(CONFINIT *ci);
void CloseInventory();
diff --git a/engines/tinsel/dw.h b/engines/tinsel/dw.h
index 34f6130a0aa..c016b5b0d54 100644
--- a/engines/tinsel/dw.h
+++ b/engines/tinsel/dw.h
@@ -64,7 +64,7 @@ typedef int HPOLYGON;
// i.e. it gets a Z position of 0
#define Z_INV_BRECT 10 // Inventory background rectangle
-#define Z_INV_MFRAME 15 // Inventory window frame
+#define Z_INV_MFRAME ((TinselVersion == 3) ? 16 : 15) // Inventory window frame
#define Z_INV_HTEXT 15 // Inventory heading text
#define Z_INV_ICONS 16 // Icons in inventory
#define Z_INV_ITEXT 995 // Icon text
diff --git a/engines/tinsel/multiobj.cpp b/engines/tinsel/multiobj.cpp
index d0af57ee61a..1ec2c944b41 100644
--- a/engines/tinsel/multiobj.cpp
+++ b/engines/tinsel/multiobj.cpp
@@ -21,10 +21,12 @@
*/
#include "tinsel/background.h"
+#include "tinsel/film.h"
#include "tinsel/multiobj.h"
#include "tinsel/handle.h"
#include "tinsel/object.h"
#include "tinsel/tinsel.h"
+#include "tinsel/noir/sysreel.h"
namespace Tinsel {
@@ -83,6 +85,28 @@ OBJECT *MultiInitObject(const MULTI_INIT *pInitTbl) {
return pFirst;
}
+OBJECT *InsertReelObj(const FREEL *reels) {
+ const MULTI_INIT *pmi = (const MULTI_INIT*)_vm->_handle->LockMem(reels->mobj);
+ // Verify that there is an image defined
+ const FRAME *frame = (const FRAME*)_vm->_handle->LockMem(pmi->hMulFrame);
+ const IMAGE *image = (const IMAGE*)_vm->_handle->LockMem(*frame);
+ assert(image);
+
+ auto pInsObj = MultiInitObject(pmi);
+ MultiInsertObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), pInsObj);
+ return pInsObj; // Result
+}
+
+const FILM *GetSystemReelFilm(SysReel reelIndex) {
+ SCNHANDLE hFilm = _vm->_systemReel->Get(reelIndex);
+ const FILM *pfilm = (const FILM *)_vm->_handle->LockMem(hFilm);
+ return pfilm;
+}
+
+OBJECT *InsertSystemReelObj(SysReel reelIndex) {
+ return InsertReelObj(GetSystemReelFilm(reelIndex)->reels);
+}
+
/**
* Inserts the multi-part object onto the specified object list.
* @param pObjList List to insert multi-part object onto
diff --git a/engines/tinsel/multiobj.h b/engines/tinsel/multiobj.h
index 897b3872817..67efe282127 100644
--- a/engines/tinsel/multiobj.h
+++ b/engines/tinsel/multiobj.h
@@ -132,6 +132,13 @@ bool MultiHasShape( // Returns TRUE if the object currently has an image
void MultiForceRedraw(
OBJECT *pMultiObj); // multi-part object to be forced
+struct FREEL;
+OBJECT* InsertReelObj(const FREEL *reels);
+struct FILM;
+enum class SysReel;
+const FILM* GetSystemReelFilm(SysReel reelIndex);
+OBJECT* InsertSystemReelObj(SysReel reelIndex);
+
} // End of namespace Tinsel
#endif // TINSEL_MULTIOBJ_H
diff --git a/engines/tinsel/noir/sysreel.h b/engines/tinsel/noir/sysreel.h
index b5f23c539ec..a003751fcb7 100644
--- a/engines/tinsel/noir/sysreel.h
+++ b/engines/tinsel/noir/sysreel.h
@@ -35,6 +35,7 @@ enum class SysReel {
CURSOR = 11,
INVMAIN = 15,
SLIDER = 16,
+ CONVERSATION_FRAME = 19,
OPTIONS_MENU = 21,
LOADSAVE_MENU = 22,
QUIT_MENU = 23,
@@ -52,6 +53,7 @@ public:
SCNHANDLE Get(SysReel index);
void Set(int32 index, SCNHANDLE reel);
+
private:
const static int32 MAX_SYSREELS = 0x28;
More information about the Scummvm-git-logs
mailing list