From 4f8cf1ea4b7bb329c78cfe1b907b408fa6c9ce18 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 4 Sep 2011 20:22:00 -0400 Subject: PEGASUS: Implement very basic hotspot loading Need to get more complex regions loaded, though... will be a major problem --- engines/pegasus/hotspot.cpp | 218 ++++++++++++++++++++++++++ engines/pegasus/hotspot.h | 114 ++++++++++++++ engines/pegasus/module.mk | 1 + engines/pegasus/neighborhood/neighborhood.cpp | 45 ++++++ engines/pegasus/neighborhood/neighborhood.h | 5 + 5 files changed, 383 insertions(+) create mode 100755 engines/pegasus/hotspot.cpp create mode 100755 engines/pegasus/hotspot.h diff --git a/engines/pegasus/hotspot.cpp b/engines/pegasus/hotspot.cpp new file mode 100755 index 0000000000..f97ad1d290 --- /dev/null +++ b/engines/pegasus/hotspot.cpp @@ -0,0 +1,218 @@ +/* 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. + * + * Additional copyright for this file: + * Copyright (C) 1995-1997 Presto Studios, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "pegasus/hotspot.h" + +namespace Pegasus { + +HotspotList g_allHotspots; + +Hotspot::Hotspot(const tHotSpotID id) : MMIDObject(id) { + _spotFlags = kNoHotSpotFlags; + _spotActive = false; +} + +Hotspot::~Hotspot() { +} + +void Hotspot::setArea(const Common::Rect &area) { + _spotArea = area; +} + +void Hotspot::setArea(const tCoordType left, const tCoordType top, const tCoordType right, const tCoordType bottom) { + _spotArea = Common::Rect(left, top, right, bottom); +} + +void Hotspot::getBoundingBox(Common::Rect &r) const { + r = _spotArea; +} + +void Hotspot::getCenter(Common::Point &pt) const { + pt.x = (_spotArea.left + _spotArea.right) / 2; + pt.y = (_spotArea.top + _spotArea.bottom) / 2; +} + +void Hotspot::getCenter(tCoordType &h, tCoordType &v) const { + h = (_spotArea.left + _spotArea.right) / 2; + v = (_spotArea.top + _spotArea.bottom) / 2; +} + +void Hotspot::setActive() { + _spotActive = true; +} + +void Hotspot::setInactive() { + _spotActive = false; +} + +void Hotspot::setHotspotFlags(const tHotSpotFlags flags) { + _spotFlags = flags; +} + +void Hotspot::setMaskedHotspotFlags(const tHotSpotFlags flags, const tHotSpotFlags mask) { + _spotFlags = (_spotFlags & ~mask) | flags; +} + +bool Hotspot::isSpotActive() const { + return _spotActive; +} + +void Hotspot::moveSpotTo(const tCoordType h, const tCoordType v) { + _spotArea.moveTo(h, v); +} + +void Hotspot::moveSpotTo(const Common::Point pt) { + _spotArea.moveTo(pt); +} + +void Hotspot::moveSpot(const tCoordType h, const tCoordType v) { + _spotArea.translate(h, v); +} + +void Hotspot::moveSpot(const Common::Point pt) { + _spotArea.translate(pt.x, pt.y); +} + +bool Hotspot::pointInSpot(const Common::Point where) const { + return _spotActive && _spotArea.contains(where); +} + +tHotSpotFlags Hotspot::getHotspotFlags() const { + return _spotFlags; +} + +HotspotList::HotspotList() { +} + +HotspotList::~HotspotList() { + // TODO: Should this call deleteHotspots()? +} + +void HotspotList::deleteHotspots() { + for (HotspotIterator it = begin(); it != end(); it++) + delete *it; + + clear(); +} + +Hotspot *HotspotList::findHotspot(const Common::Point where) { + for (HotspotIterator it = begin(); it != end(); it++) + if ((*it)->pointInSpot(where)) + return *it; + + return 0; +} + +tHotSpotID HotspotList::findHotspotID(const Common::Point where) { + Hotspot *hotspot = findHotspot(where); + return hotspot ? hotspot->getObjectID() : kNoHotSpotID; +} + +Hotspot *HotspotList::findHotspotByID(const tHotSpotID id) { + for (HotspotIterator it = begin(); it != end(); it++) + if ((*it)->getObjectID() == id) + return *it; + + return 0; +} + +Hotspot *HotspotList::findHotspotByMask(const tHotSpotFlags flags) { + for (HotspotIterator it = begin(); it != end(); it++) + if (((*it)->getHotspotFlags() & flags) == flags) + return *it; + + return 0; +} + +void HotspotList::activateMaskedHotspots(const tHotSpotFlags flags) { + for (HotspotIterator it = begin(); it != end(); it++) + if (flags == kNoHotSpotFlags || ((*it)->getHotspotFlags() & flags) != 0) + (*it)->setActive(); +} + +void HotspotList::deactivateAllHotspots() { + for (HotspotIterator it = begin(); it != end(); it++) + (*it)->setInactive(); +} + +void HotspotList::deactivateMaskedHotspots(const tHotSpotFlags flags) { + for (HotspotIterator it = begin(); it != end(); it++) + if (((*it)->getHotspotFlags() & flags) != 0) + (*it)->setInactive(); +} + +void HotspotList::activateOneHotspot(const tHotSpotID id) { + for (HotspotIterator it = begin(); it != end(); it++) { + if ((*it)->getObjectID() == id) { + (*it)->setActive(); + return; + } + } +} + +void HotspotList::deactivateOneHotspot(const tHotSpotID id) { + for (HotspotIterator it = begin(); it != end(); it++) { + if ((*it)->getObjectID() == id) { + (*it)->setInactive(); + return; + } + } +} + +void HotspotList::removeOneHotspot(const tHotSpotID id) { + for (HotspotIterator it = begin(); it != end(); it++) { + if ((*it)->getObjectID() == id) { + erase(it); + return; + } + } +} + +void HotspotList::removeMaskedHotspots(const tHotSpotFlags flags) { + if (flags != kNoHotSpotFlags) { + for (HotspotIterator it = begin(); it != end(); ) { + if (((*it)->getHotspotFlags() & flags) != 0) + it = erase(it); + else + it++; + } + } else { + clear(); + } +} + +void HotspotList::setHotspotRect(const tHotSpotID id, const Common::Rect &r) { + Hotspot *hotspot = findHotspotByID(id); + if (hotspot) + hotspot->setArea(r); +} + +void HotspotList::getHotspotRect(const tHotSpotID id, Common::Rect &r) { + Hotspot *hotspot = findHotspotByID(id); + if (hotspot) + hotspot->getBoundingBox(r); +} + +} // End of namespace Pegasus diff --git a/engines/pegasus/hotspot.h b/engines/pegasus/hotspot.h new file mode 100755 index 0000000000..97bbf37832 --- /dev/null +++ b/engines/pegasus/hotspot.h @@ -0,0 +1,114 @@ +/* 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. + * + * Additional copyright for this file: + * Copyright (C) 1995-1997 Presto Studios, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PEGASUS_HOTSPOT_H +#define PEGASUS_HOTSPOT_H + +#include "common/list.h" +#include "common/rect.h" + +#include "pegasus/constants.h" +#include "pegasus/types.h" +#include "pegasus/MMShell/Utilities/MMIDObject.h" + +/* + + Hot spots combine a pixel area, an ID value and an active flag. + + A point is considered in a hot spot if the point is in the hot spot's pixel area and + the active flag is set. + + In addition, hot spots have a 32 bit word of bit flags for filtering use. + +*/ + +namespace Pegasus { + +class Hotspot : public MMIDObject { +public: + Hotspot(const tHotSpotID); + virtual ~Hotspot(); + + void setArea(const Common::Rect &); + void setArea(const tCoordType, const tCoordType, const tCoordType, const tCoordType); + void getBoundingBox(Common::Rect &) const; + void getCenter(Common::Point&) const; + void getCenter(tCoordType&, tCoordType&) const; + + void moveSpotTo(const tCoordType, const tCoordType); + void moveSpotTo(const Common::Point); + void moveSpot(const tCoordType, const tCoordType); + void moveSpot(const Common::Point); + + bool pointInSpot(const Common::Point) const; + + void setActive(); + void setInactive(); + bool isSpotActive() const; + + tHotSpotFlags getHotspotFlags() const; + void setHotspotFlags(const tHotSpotFlags); + void setMaskedHotspotFlags(const tHotSpotFlags flags, const tHotSpotFlags mask); + +protected: + Common::Rect _spotArea; + tHotSpotFlags _spotFlags; + bool _spotActive; +}; + +class HotspotList : public Common::List { +public: + HotspotList(); + virtual ~HotspotList(); + + void deleteHotspots(); + + Hotspot *findHotspot(const Common::Point); + tHotSpotID findHotspotID(const Common::Point); + Hotspot * findHotspotByID(const tHotSpotID); + Hotspot * findHotspotByMask(const tHotSpotFlags); + + void activateMaskedHotspots(const tHotSpotFlags = kNoHotSpotFlags); + void deactivateAllHotspots(); + void deactivateMaskedHotspots(const tHotSpotFlags); + + void activateOneHotspot(const tHotSpotID); + void deactivateOneHotspot(const tHotSpotID); + + void removeOneHotspot(const tHotSpotID); + void removeMaskedHotspots(const tHotSpotFlags = kNoHotSpotFlags); + + void setHotspotRect(const tHotSpotID, const Common::Rect&); + void getHotspotRect(const tHotSpotID, Common::Rect&); +}; + +typedef HotspotList::iterator HotspotIterator; + +// FIXME: Remove global construction +extern HotspotList g_allHotspots; + +} // End of namespace Pegasus + +#endif diff --git a/engines/pegasus/module.mk b/engines/pegasus/module.mk index be50ecb48a..7a2d5b1a2c 100644 --- a/engines/pegasus/module.mk +++ b/engines/pegasus/module.mk @@ -6,6 +6,7 @@ MODULE_OBJS = \ detection.o \ gamestate.o \ graphics.o \ + hotspot.o \ menu.o \ overview.o \ pegasus.o \ diff --git a/engines/pegasus/neighborhood/neighborhood.cpp b/engines/pegasus/neighborhood/neighborhood.cpp index 3d47dbfb13..1a22831f5e 100644 --- a/engines/pegasus/neighborhood/neighborhood.cpp +++ b/engines/pegasus/neighborhood/neighborhood.cpp @@ -38,6 +38,10 @@ Neighborhood::Neighborhood(PegasusEngine *vm, const Common::String &resName, tNe } Neighborhood::~Neighborhood() { + for (HotspotIterator it = _neighborhoodHotspots.begin(); it != _neighborhoodHotspots.end(); it++) + g_allHotspots.remove(*it); + + _neighborhoodHotspots.deleteHotspots(); } void Neighborhood::init() { @@ -91,6 +95,8 @@ void Neighborhood::init() { _zoomTable.loadFromStream(stream); delete stream; + createNeighborhoodSpots(); + // TODO: AI, movies, notifications, buncha other stuff } @@ -222,5 +228,44 @@ tCanOpenDoorReason Neighborhood::canOpenDoor(DoorTable::Entry &entry) { return kCantOpenNoDoor; } +void Neighborhood::createNeighborhoodSpots() { + Common::SeekableReadStream *hotspotList = _vm->_resFork->getResource(MKTAG('H', 'S', 'L', 's'), _resName); + if (!hotspotList) + error("Could not load neighborhood hotspots"); + + uint32 hotspotCount = hotspotList->readUint32BE(); + + while (hotspotCount--) { + uint16 id = hotspotList->readUint16BE(); + uint32 flags = hotspotList->readUint32BE(); + uint32 rgnSize = hotspotList->readUint32BE(); + + // duplicate of rgnSize + hotspotList->readUint16BE(); + + Common::Rect boundingBox; + boundingBox.top = hotspotList->readUint16BE(); + boundingBox.left = hotspotList->readUint16BE(); + boundingBox.bottom = hotspotList->readUint16BE(); + boundingBox.right = hotspotList->readUint16BE(); + + debug(0, "Hotspot[%d]: Flags = %08x", id, flags); + boundingBox.debugPrint(0, "\tBounding Box:"); + + // TODO: Handle non-rectangular hotspots + if (rgnSize != 10) + warning("Non-rectangular hotspot found - %d extra bytes", rgnSize - 10); + hotspotList->skip(rgnSize - 10); + + Hotspot *hotspot = new Hotspot(id); + hotspot->setHotspotFlags(flags); + hotspot->setArea(boundingBox); + + g_allHotspots.push_back(hotspot); + _neighborhoodHotspots.push_back(hotspot); + } + + delete hotspotList; +} } // End of namespace Pegasus diff --git a/engines/pegasus/neighborhood/neighborhood.h b/engines/pegasus/neighborhood/neighborhood.h index 0b8be864e1..73f6c49d3c 100644 --- a/engines/pegasus/neighborhood/neighborhood.h +++ b/engines/pegasus/neighborhood/neighborhood.h @@ -28,6 +28,7 @@ #include "common/str.h" +#include "pegasus/hotspot.h" #include "pegasus/neighborhood/door.h" #include "pegasus/neighborhood/exit.h" #include "pegasus/neighborhood/extra.h" @@ -79,6 +80,8 @@ public: tCanOpenDoorReason canOpenDoor(DoorTable::Entry &entry); protected: + virtual void createNeighborhoodSpots(); + PegasusEngine *_vm; Common::String _resName; tNeighborhoodID _neighborhoodID; @@ -93,6 +96,8 @@ protected: ZoomTable _zoomTable; tAlternateID _currentAlternate; + + HotspotList _neighborhoodHotspots; }; } // End of namespace Pegasus -- cgit v1.2.3