From 3c5fb26a913b1b8c97da6a0ef0b6b0f2f1498b4b Mon Sep 17 00:00:00 2001 From: Arnaud Boutonné Date: Fri, 11 Feb 2011 07:12:29 +0000 Subject: HUGO: refactoring: move boundaries to object class svn-id: r55879 --- engines/hugo/display.cpp | 22 +++--- engines/hugo/display.h | 19 +++-- engines/hugo/hugo.cpp | 182 +------------------------------------------- engines/hugo/hugo.h | 32 -------- engines/hugo/inventory.h | 4 +- engines/hugo/object.cpp | 175 +++++++++++++++++++++++++++++++++++++++++- engines/hugo/object.h | 17 +++++ engines/hugo/object_v1d.cpp | 18 ++--- engines/hugo/object_v1w.cpp | 18 ++--- engines/hugo/object_v2d.cpp | 18 ++--- engines/hugo/object_v3d.cpp | 18 ++--- engines/hugo/route.cpp | 11 +-- engines/hugo/route.h | 9 ++- 13 files changed, 265 insertions(+), 278 deletions(-) (limited to 'engines') diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp index 09e04a96e1..4d6303305d 100644 --- a/engines/hugo/display.cpp +++ b/engines/hugo/display.cpp @@ -199,14 +199,14 @@ void Screen::setBackgroundColor(const uint16 color) { overlayState_t Screen::findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) { debugC(4, kDebugDisplay, "findOvl()"); - for (; y < seq_p->lines; y++) { // Each line in object - image_pt ovb_p = _vm->getBaseBoundaryOverlay() + ((uint16)(dst_p - _frontBuffer) >> 3); // Ptr into overlay bits - if (*ovb_p & (0x80 >> ((uint16)(dst_p - _frontBuffer) & 7))) // Overlay bit is set - return FG; // Found a bit - must be foreground + for (; y < seq_p->lines; y++) { // Each line in object + byte ovb = _vm->_object->getBaseBoundary((uint16)(dst_p - _frontBuffer) >> 3); // Ptr into overlay bits + if (ovb & (0x80 >> ((uint16)(dst_p - _frontBuffer) & 7))) // Overlay bit is set + return kOvlForeground; // Found a bit - must be foreground dst_p += kXPix; } - return BG; // No bits set, must be background + return kOvlBackground; // No bits set, must be background } /** @@ -218,19 +218,17 @@ void Screen::displayFrame(const int sx, const int sy, seq_t *seq, const bool for image_pt image = seq->imagePtr; // Ptr to object image data image_pt subFrontBuffer = &_frontBuffer[sy * kXPix + sx]; // Ptr to offset in _frontBuffer - image_pt overlay = &_vm->getFirstOverlay()[(sy * kXPix + sx) >> 3]; // Ptr to overlay data int16 frontBufferwrap = kXPix - seq->x2 - 1; // Wraps dest_p after each line int16 imageWrap = seq->bytesPerLine8 - seq->x2 - 1; - - overlayState_t overlayState = UNDEF; // Overlay state of object + overlayState_t overlayState = kOvlUndef; // Overlay state of object for (uint16 y = 0; y < seq->lines; y++) { // Each line in object for (uint16 x = 0; x <= seq->x2; x++) { if (*image) { // Non-transparent - overlay = _vm->getFirstOverlay() + ((uint16)(subFrontBuffer - _frontBuffer) >> 3); // Ptr into overlay bits - if (*overlay & (0x80 >> ((uint16)(subFrontBuffer - _frontBuffer) & 7))) { // Overlay bit is set - if (overlayState == UNDEF) // Overlay defined yet? + byte ovlBound = _vm->_object->getFirstOverlay((uint16)(subFrontBuffer - _frontBuffer) >> 3); // Ptr into overlay bits + if (ovlBound & (0x80 >> ((uint16)(subFrontBuffer - _frontBuffer) & 7))) { // Overlay bit is set + if (overlayState == kOvlUndef) // Overlay defined yet? overlayState = findOvl(seq, subFrontBuffer, y);// No, find it. - if (foreFl || overlayState == FG) // Object foreground + if (foreFl || overlayState == kOvlForeground) // Object foreground *subFrontBuffer = *image; // Copy pixel } else { // No overlay *subFrontBuffer = *image; // Copy pixel diff --git a/engines/hugo/display.h b/engines/hugo/display.h index 29d7bb7722..05a9546243 100644 --- a/engines/hugo/display.h +++ b/engines/hugo/display.h @@ -34,13 +34,7 @@ #define HUGO_DISPLAY_H namespace Hugo { -enum overlayState_t {UNDEF, FG, BG}; // Overlay state - -static const int kShapeSize = 24; -static const int kFontLength = 128; // Number of chars in font -static const int kFontSize = 1200; // Max size of font data -static const int kNumFonts = 3; // Number of dib fonts -static const int kCenter = -1; // Used to center text in x +enum overlayState_t {kOvlUndef, kOvlForeground, kOvlBackground}; // Overlay state struct rect_t { // Rectangle used in Display list int16 x; // Position in dib @@ -49,6 +43,8 @@ struct rect_t { // Rectangle used in Display int16 dy; // height }; +static const int kCenter = -1; // Used to center text in x + /** * A black and white Windows-style arrow cursor (12x20). * 0 = Black (#000000 in 24-bit RGB). @@ -56,7 +52,6 @@ struct rect_t { // Rectangle used in Display * 15 = White (#FFFFFF in 24-bit RGB). * This cursor comes from Mohawk engine. */ - static const byte stdMouseCursor[] = { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 15, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -79,8 +74,6 @@ static const byte stdMouseCursor[] = { 1, 1, 1, 1, 1, 1, 1, 0, 15, 15, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1 }; -static const byte stdMouseCursorHeight = 20; -static const byte stdMouseCursorWidth = 12; class Screen { public: @@ -145,6 +138,12 @@ protected: static const int kRectListSize = 16; // Size of add/restore rect lists static const int kBlitListSize = kRectListSize * 2; // Size of dirty rect blit list + static const int kShapeSize = 24; + static const int kFontLength = 128; // Number of chars in font + static const int kFontSize = 1200; // Max size of font data + static const int kNumFonts = 3; // Number of dib fonts + static const byte stdMouseCursorHeight = 20; + static const byte stdMouseCursorWidth = 12; inline bool isInX(const int16 x, const rect_t *rect) const; inline bool isInY(const int16 y, const rect_t *rect) const; diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp index e97cfbbd85..dec3ab59d3 100644 --- a/engines/hugo/hugo.cpp +++ b/engines/hugo/hugo.cpp @@ -50,11 +50,6 @@ namespace Hugo { HugoEngine *HugoEngine::s_Engine = 0; -overlay_t HugoEngine::_boundary; -overlay_t HugoEngine::_overlay; -overlay_t HugoEngine::_ovlBase; -overlay_t HugoEngine::_objBound; - maze_t _maze; // Default to not in maze hugo_boot_t _boot; // Boot info structure file @@ -855,147 +850,14 @@ void HugoEngine::readScreenFiles(const int screenNum) { _file->readBackground(screenNum); // Scenery file memcpy(_screen->getBackBuffer(), _screen->getFrontBuffer(), sizeof(_screen->getFrontBuffer())); // Make a copy - _file->readOverlay(screenNum, _boundary, kOvlBoundary); // Boundary file - _file->readOverlay(screenNum, _overlay, kOvlOverlay); // Overlay file - _file->readOverlay(screenNum, _ovlBase, kOvlBase); // Overlay base file + _file->readOverlay(screenNum, _object->_boundary, kOvlBoundary); // Boundary file + _file->readOverlay(screenNum, _object->_overlay, kOvlOverlay); // Overlay file + _file->readOverlay(screenNum, _object->_ovlBase, kOvlBase); // Overlay base file // Suppress a boundary used in H3 DOS in 'Crash' screen, which blocks // pathfinding and is useless. if ((screenNum == 0) && (_gameVariant == kGameVariantH3Dos)) - clearScreenBoundary(50, 311, 152); -} - -/** -* Return maximum allowed movement (from zero to vx) such that object does -* not cross a boundary (either background or another object) -*/ -int HugoEngine::deltaX(const int x1, const int x2, const int vx, int y) const { -// Explanation of algorithm: The boundaries are drawn as contiguous -// lines 1 pixel wide. Since DX,DY are not necessarily 1, we must -// detect boundary crossing. If vx positive, examine each pixel from -// x1 old to x2 new, else x2 old to x1 new, both at the y2 line. -// If vx zero, no need to check. If vy non-zero then examine each -// pixel on the line segment x1 to x2 from y old to y new. -// Fix from Hugo I v1.5: -// Note the diff is munged in the return statement to cater for a special -// cases arising from differences in image widths from one sequence to -// another. The problem occurs reversing direction at a wall where the -// new image intersects before the object can move away. This is cured -// by comparing the intersection with half the object width pos. If the -// intersection is in the other half wrt the intended direction, use the -// desired vx, else use the computed delta. i.e. believe the desired vx - - debugC(3, kDebugEngine, "deltaX(%d, %d, %d, %d)", x1, x2, vx, y); - - if (vx == 0) - return 0; // Object stationary - - y *= kCompLineSize; // Offset into boundary file - if (vx > 0) { - // Moving to right - for (int i = x1 >> 3; i <= (x2 + vx) >> 3; i++) {// Search by byte - int b = Utils::firstBit((byte)(_boundary[y + i] | _objBound[y + i])); - if (b < 8) { // b is index or 8 - // Compute x of boundary and test if intersection - b += i << 3; - if ((b >= x1) && (b <= x2 + vx)) - return (b < x1 + ((x2 - x1) >> 1)) ? vx : b - x2 - 1; // return dx - } - } - } else { - // Moving to left - for (int i = x2 >> 3; i >= (x1 + vx) >> 3; i--) {// Search by byte - int b = Utils::lastBit((byte)(_boundary[y + i] | _objBound[y + i])); - if (b < 8) { // b is index or 8 - // Compute x of boundary and test if intersection - b += i << 3; - if ((b >= x1 + vx) && (b <= x2)) - return (b > x1 + ((x2 - x1) >> 1)) ? vx : b - x1 + 1; // return dx - } - } - } - return vx; -} - -/** -* Similar to Delta_x, but for movement in y direction. Special case of -* bytes at end of line segment; must only count boundary bits falling on -* line segment. -*/ -int HugoEngine::deltaY(const int x1, const int x2, const int vy, const int y) const { - debugC(3, kDebugEngine, "deltaY(%d, %d, %d, %d)", x1, x2, vy, y); - - if (vy == 0) - return 0; // Object stationary - - int inc = (vy > 0) ? 1 : -1; - for (int j = y + inc; j != (y + vy + inc); j += inc) { //Search by byte - for (int i = x1 >> 3; i <= x2 >> 3; i++) { - int b = _boundary[j * kCompLineSize + i] | _objBound[j * kCompLineSize + i]; - if (b != 0) { // Any bit set - // Make sure boundary bits fall on line segment - if (i == (x2 >> 3)) // Adjust right end - b &= 0xff << ((i << 3) + 7 - x2); - else if (i == (x1 >> 3)) // Adjust left end - b &= 0xff >> (x1 - (i << 3)); - if (b) - return j - y - inc; - } - } - } - return vy; -} - -/** -* Store a horizontal line segment in the object boundary file -*/ -void HugoEngine::storeBoundary(const int x1, const int x2, const int y) { - debugC(5, kDebugEngine, "storeBoundary(%d, %d, %d)", x1, x2, y); - - for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line - byte *b = &_objBound[y * kCompLineSize + i];// get boundary byte - if (i == x2 >> 3) // Adjust right end - *b |= 0xff << ((i << 3) + 7 - x2); - else if (i == x1 >> 3) // Adjust left end - *b |= 0xff >> (x1 - (i << 3)); - else - *b = 0xff; - } -} - -/** -* Clear a horizontal line segment in the object boundary file -*/ -void HugoEngine::clearBoundary(const int x1, const int x2, const int y) { - debugC(5, kDebugEngine, "clearBoundary(%d, %d, %d)", x1, x2, y); - - for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line - byte *b = &_objBound[y * kCompLineSize + i];// get boundary byte - if (i == x2 >> 3) // Adjust right end - *b &= ~(0xff << ((i << 3) + 7 - x2)); - else if (i == x1 >> 3) // Adjust left end - *b &= ~(0xff >> (x1 - (i << 3))); - else - *b = 0; - } -} - -/** -* Clear a horizontal line segment in the screen boundary file -* Used to fix some data issues -*/ -void HugoEngine::clearScreenBoundary(const int x1, const int x2, const int y) { - debugC(5, kDebugEngine, "clearScreenBoundary(%d, %d, %d)", x1, x2, y); - - for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line - byte *b = &_boundary[y * kCompLineSize + i];// get boundary byte - if (i == x2 >> 3) // Adjust right end - *b &= ~(0xff << ((i << 3) + 7 - x2)); - else if (i == x1 >> 3) // Adjust left end - *b &= ~(0xff >> (x1 - (i << 3))); - else - *b = 0; - } + _object->clearScreenBoundary(50, 311, 152); } /** @@ -1039,42 +901,6 @@ void HugoEngine::setNewScreen(const int screenNum) { _object->setCarriedScreen(screenNum); // Carried objects } -/** -* An object has collided with a boundary. See if any actions are required -*/ -void HugoEngine::boundaryCollision(object_t *obj) { - debugC(1, kDebugEngine, "boundaryCollision"); - - if (obj == _hero) { - // Hotspots only relevant to HERO - int x; - if (obj->vx > 0) - x = obj->x + obj->currImagePtr->x2; - else - x = obj->x + obj->currImagePtr->x1; - int y = obj->y + obj->currImagePtr->y2; - - for (int i = 0; _hotspots[i].screenIndex >= 0; i++) { - hotspot_t *hotspot = &_hotspots[i]; - if (hotspot->screenIndex == obj->screenIndex) - if ((x >= hotspot->x1) && (x <= hotspot->x2) && (y >= hotspot->y1) && (y <= hotspot->y2)) { - _scheduler->insertActionList(hotspot->actIndex); - break; - } - } - } else { - // Check whether an object collided with HERO - int dx = _hero->x + _hero->currImagePtr->x1 - obj->x - obj->currImagePtr->x1; - int dy = _hero->y + _hero->currImagePtr->y2 - obj->y - obj->currImagePtr->y2; - // If object's radius is infinity, use a closer value - int8 radius = obj->radius; - if (radius < 0) - radius = kStepDx * 2; - if ((abs(dx) <= radius) && (abs(dy) <= radius)) - _scheduler->insertActionList(obj->actIndex); - } -} - /** * Add up all the object values and all the bonus points */ diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h index ea67927e11..3799e32e32 100644 --- a/engines/hugo/hugo.h +++ b/engines/hugo/hugo.h @@ -140,11 +140,6 @@ enum istate_t {kInventoryOff, kInventoryUp, kInventoryDown, kInventoryActive}; */ enum vstate_t {kViewIdle, kViewIntroInit, kViewIntro, kViewPlay, kViewInvent, kViewExit}; -/** -* Purpose of an automatic route -*/ -enum go_t {kRouteSpace, kRouteExit, kRouteLook, kRouteGet}; - /** * Enumerate whether object is foreground, background or 'floating' * If floating, HERO can collide with it and fore/back ground is determined @@ -305,37 +300,18 @@ public: char *useBG(const char *name); - int deltaX(const int x1, const int x2, const int vx, int y) const; - int deltaY(const int x1, const int x2, const int vy, const int y) const; - int8 getTPS() const; void initGame(const HugoGameDescription *gd); void initGamePart(const HugoGameDescription *gd); - void boundaryCollision(object_t *obj); - void clearBoundary(const int x1, const int x2, const int y); - void clearScreenBoundary(const int x1, const int x2, const int y); void endGame(); void initStatus(); void readScreenFiles(const int screen); void screenActions(const int screen); void setNewScreen(const int screen); void shutdown(); - void storeBoundary(const int x1, const int x2, const int y); void syncSoundSettings(); - overlay_t &getBoundaryOverlay() { - return _boundary; - } - overlay_t &getObjectBoundaryOverlay() { - return _objBound; - } - overlay_t &getBaseBoundaryOverlay() { - return _ovlBase; - } - overlay_t &getFirstOverlay() { - return _overlay; - } status_t &getGameStatus() { return _status; } @@ -407,14 +383,6 @@ private: // foreground stationary objects and baselines for those objects (used to // determine foreground/background wrt moving objects) -// Vinterstum: These shouldn't be static, but we get weird pathfinding issues (and Valgrind warnings) without. -// Needs more investigation. Alignment issues? - - static overlay_t _boundary; // Boundary overlay file - static overlay_t _overlay; // First overlay file - static overlay_t _ovlBase; // First overlay base file - static overlay_t _objBound; // Boundary file marks object baselines - GameType _gameType; Common::Platform _platform; bool _packedFl; diff --git a/engines/hugo/inventory.h b/engines/hugo/inventory.h index f4263de5c4..84bc29ea1b 100644 --- a/engines/hugo/inventory.h +++ b/engines/hugo/inventory.h @@ -44,9 +44,9 @@ public: InventoryHandler(HugoEngine *vm); void setInventoryObjId(int16 objId) { _inventoryObjId = objId; } - int16 getInventoryObjId() { return _inventoryObjId; } void setInventoryState(istate_t state) { _inventoryState = state; } - istate_t getInventoryState() { return _inventoryState; } + int16 getInventoryObjId() const { return _inventoryObjId; } + istate_t getInventoryState() const { return _inventoryState; } int16 processInventory(const invact_t action, ...); void runInventory(); diff --git a/engines/hugo/object.cpp b/engines/hugo/object.cpp index 5f79bc0d5a..5db53fdd79 100644 --- a/engines/hugo/object.cpp +++ b/engines/hugo/object.cpp @@ -50,6 +50,10 @@ namespace Hugo { ObjectHandler::ObjectHandler(HugoEngine *vm) : _vm(vm), _objects(0) { _numObj = 0; _objCount = 0; + memset(_objBound, '\0', sizeof(overlay_t)); + memset(_boundary, '\0', sizeof(overlay_t)); + memset(_overlay, '\0', sizeof(overlay_t)); + memset(_ovlBase, '\0', sizeof(overlay_t)); } ObjectHandler::~ObjectHandler() { @@ -591,7 +595,176 @@ void ObjectHandler::readObjectImages() { bool ObjectHandler::checkBoundary(int16 x, int16 y) { // Check if Boundary bit set - return (_vm->getBoundaryOverlay()[y * kCompLineSize + x / 8] & (0x80 >> x % 8)) != 0; + return (_boundary[y * kCompLineSize + x / 8] & (0x80 >> x % 8)) != 0; +} + +/** +* Return maximum allowed movement (from zero to vx) such that object does +* not cross a boundary (either background or another object) +*/ +int ObjectHandler::deltaX(const int x1, const int x2, const int vx, int y) const { +// Explanation of algorithm: The boundaries are drawn as contiguous +// lines 1 pixel wide. Since DX,DY are not necessarily 1, we must +// detect boundary crossing. If vx positive, examine each pixel from +// x1 old to x2 new, else x2 old to x1 new, both at the y2 line. +// If vx zero, no need to check. If vy non-zero then examine each +// pixel on the line segment x1 to x2 from y old to y new. +// Fix from Hugo I v1.5: +// Note the diff is munged in the return statement to cater for a special +// cases arising from differences in image widths from one sequence to +// another. The problem occurs reversing direction at a wall where the +// new image intersects before the object can move away. This is cured +// by comparing the intersection with half the object width pos. If the +// intersection is in the other half wrt the intended direction, use the +// desired vx, else use the computed delta. i.e. believe the desired vx + + debugC(3, kDebugEngine, "deltaX(%d, %d, %d, %d)", x1, x2, vx, y); + + if (vx == 0) + return 0; // Object stationary + + y *= kCompLineSize; // Offset into boundary file + if (vx > 0) { + // Moving to right + for (int i = x1 >> 3; i <= (x2 + vx) >> 3; i++) {// Search by byte + int b = Utils::firstBit((byte)(_boundary[y + i] | _objBound[y + i])); + if (b < 8) { // b is index or 8 + // Compute x of boundary and test if intersection + b += i << 3; + if ((b >= x1) && (b <= x2 + vx)) + return (b < x1 + ((x2 - x1) >> 1)) ? vx : b - x2 - 1; // return dx + } + } + } else { + // Moving to left + for (int i = x2 >> 3; i >= (x1 + vx) >> 3; i--) {// Search by byte + int b = Utils::lastBit((byte)(_boundary[y + i] | _objBound[y + i])); + if (b < 8) { // b is index or 8 + // Compute x of boundary and test if intersection + b += i << 3; + if ((b >= x1 + vx) && (b <= x2)) + return (b > x1 + ((x2 - x1) >> 1)) ? vx : b - x1 + 1; // return dx + } + } + } + return vx; +} + +/** +* Similar to Delta_x, but for movement in y direction. Special case of +* bytes at end of line segment; must only count boundary bits falling on +* line segment. +*/ +int ObjectHandler::deltaY(const int x1, const int x2, const int vy, const int y) const { + debugC(3, kDebugEngine, "deltaY(%d, %d, %d, %d)", x1, x2, vy, y); + + if (vy == 0) + return 0; // Object stationary + + int inc = (vy > 0) ? 1 : -1; + for (int j = y + inc; j != (y + vy + inc); j += inc) { //Search by byte + for (int i = x1 >> 3; i <= x2 >> 3; i++) { + int b = _boundary[j * kCompLineSize + i] | _objBound[j * kCompLineSize + i]; + if (b != 0) { // Any bit set + // Make sure boundary bits fall on line segment + if (i == (x2 >> 3)) // Adjust right end + b &= 0xff << ((i << 3) + 7 - x2); + else if (i == (x1 >> 3)) // Adjust left end + b &= 0xff >> (x1 - (i << 3)); + if (b) + return j - y - inc; + } + } + } + return vy; +} + +/** +* Store a horizontal line segment in the object boundary file +*/ +void ObjectHandler::storeBoundary(const int x1, const int x2, const int y) { + debugC(5, kDebugEngine, "storeBoundary(%d, %d, %d)", x1, x2, y); + + for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line + byte *b = &_objBound[y * kCompLineSize + i];// get boundary byte + if (i == x2 >> 3) // Adjust right end + *b |= 0xff << ((i << 3) + 7 - x2); + else if (i == x1 >> 3) // Adjust left end + *b |= 0xff >> (x1 - (i << 3)); + else + *b = 0xff; + } +} + +/** +* Clear a horizontal line segment in the object boundary file +*/ +void ObjectHandler::clearBoundary(const int x1, const int x2, const int y) { + debugC(5, kDebugEngine, "clearBoundary(%d, %d, %d)", x1, x2, y); + + for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line + byte *b = &_objBound[y * kCompLineSize + i];// get boundary byte + if (i == x2 >> 3) // Adjust right end + *b &= ~(0xff << ((i << 3) + 7 - x2)); + else if (i == x1 >> 3) // Adjust left end + *b &= ~(0xff >> (x1 - (i << 3))); + else + *b = 0; + } +} + +/** +* Clear a horizontal line segment in the screen boundary file +* Used to fix some data issues +*/ +void ObjectHandler::clearScreenBoundary(const int x1, const int x2, const int y) { + debugC(5, kDebugEngine, "clearScreenBoundary(%d, %d, %d)", x1, x2, y); + + for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line + byte *b = &_boundary[y * kCompLineSize + i];// get boundary byte + if (i == x2 >> 3) // Adjust right end + *b &= ~(0xff << ((i << 3) + 7 - x2)); + else if (i == x1 >> 3) // Adjust left end + *b &= ~(0xff >> (x1 - (i << 3))); + else + *b = 0; + } +} + +/** +* An object has collided with a boundary. See if any actions are required +*/ +void ObjectHandler::boundaryCollision(object_t *obj) { + debugC(1, kDebugEngine, "boundaryCollision"); + + if (obj == _vm->_hero) { + // Hotspots only relevant to HERO + int x; + if (obj->vx > 0) + x = obj->x + obj->currImagePtr->x2; + else + x = obj->x + obj->currImagePtr->x1; + int y = obj->y + obj->currImagePtr->y2; + + for (int i = 0; _vm->_hotspots[i].screenIndex >= 0; i++) { + hotspot_t *hotspot = &_vm->_hotspots[i]; + if (hotspot->screenIndex == obj->screenIndex) + if ((x >= hotspot->x1) && (x <= hotspot->x2) && (y >= hotspot->y1) && (y <= hotspot->y2)) { + _vm->_scheduler->insertActionList(hotspot->actIndex); + break; + } + } + } else { + // Check whether an object collided with HERO + int dx = _vm->_hero->x + _vm->_hero->currImagePtr->x1 - obj->x - obj->currImagePtr->x1; + int dy = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - obj->y - obj->currImagePtr->y2; + // If object's radius is infinity, use a closer value + int8 radius = obj->radius; + if (radius < 0) + radius = kStepDx * 2; + if ((abs(dx) <= radius) && (abs(dy) <= radius)) + _vm->_scheduler->insertActionList(obj->actIndex); + } } } // End of namespace Hugo diff --git a/engines/hugo/object.h b/engines/hugo/object.h index 736be20ef1..ce94c79103 100644 --- a/engines/hugo/object.h +++ b/engines/hugo/object.h @@ -42,9 +42,26 @@ public: ObjectHandler(HugoEngine *vm); virtual ~ObjectHandler(); + overlay_t _objBound; + overlay_t _boundary; // Boundary overlay file + overlay_t _overlay; // First overlay file + overlay_t _ovlBase; // First overlay base file + object_t *_objects; uint16 _numObj; + byte getBoundaryOverlay(uint16 index) const { return _boundary[index]; } + byte getObjectBoundary(uint16 index) const { return _objBound[index]; } + byte getBaseBoundary(uint16 index) const { return _ovlBase[index]; } + byte getFirstOverlay(uint16 index) const { return _overlay[index]; } + + int deltaX(const int x1, const int x2, const int vx, int y) const; + int deltaY(const int x1, const int x2, const int vy, const int y) const; + void boundaryCollision(object_t *obj); + void clearBoundary(const int x1, const int x2, const int y); + void clearScreenBoundary(const int x1, const int x2, const int y); + void storeBoundary(const int x1, const int x2, const int y); + virtual void homeIn(const int objIndex1, const int objIndex2, const int8 objDx, const int8 objDy) = 0; virtual void moveObjects() = 0; virtual void updateImages() = 0; diff --git a/engines/hugo/object_v1d.cpp b/engines/hugo/object_v1d.cpp index f2cac5c658..64def1435a 100644 --- a/engines/hugo/object_v1d.cpp +++ b/engines/hugo/object_v1d.cpp @@ -224,7 +224,7 @@ void ObjectHandler_v1d::moveObjects() { obj->cycling = kCycleForward; } else { obj->cycling = kCycleNotCycling; - _vm->boundaryCollision(obj); // Must have got hero! + boundaryCollision(obj); // Must have got hero! } obj->oldvx = obj->vx; obj->oldvy = obj->vy; @@ -267,7 +267,7 @@ void ObjectHandler_v1d::moveObjects() { } // Store boundaries if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); + storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); } } @@ -287,25 +287,25 @@ void ObjectHandler_v1d::moveObjects() { int y2 = obj->y + currImage->y2; // Bottom edge if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->clearBoundary(x1, x2, y2); // Clear our own boundary + clearBoundary(x1, x2, y2); // Clear our own boundary // Allowable motion wrt boundary - int dx = _vm->deltaX(x1, x2, obj->vx, y2); + int dx = deltaX(x1, x2, obj->vx, y2); if (dx != obj->vx) { // An object boundary collision! - _vm->boundaryCollision(obj); + boundaryCollision(obj); obj->vx = 0; } - int dy = _vm->deltaY(x1, x2, obj->vy, y2); + int dy = deltaY(x1, x2, obj->vy, y2); if (dy != obj->vy) { // An object boundary collision! - _vm->boundaryCollision(obj); + boundaryCollision(obj); obj->vy = 0; } if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->storeBoundary(x1, x2, y2); // Re-store our own boundary + storeBoundary(x1, x2, y2); // Re-store our own boundary obj->x += dx; // Update object position obj->y += dy; @@ -330,7 +330,7 @@ void ObjectHandler_v1d::moveObjects() { object_t *obj = &_objects[i]; // Get pointer to object seq_t *currImage = obj->currImagePtr; // Get ptr to current image if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); + clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); } // If maze mode is enabled, do special maze processing diff --git a/engines/hugo/object_v1w.cpp b/engines/hugo/object_v1w.cpp index 465427b840..0e3efbb98b 100644 --- a/engines/hugo/object_v1w.cpp +++ b/engines/hugo/object_v1w.cpp @@ -236,7 +236,7 @@ void ObjectHandler_v1w::moveObjects() { obj->cycling = kCycleForward; } else { obj->cycling = kCycleNotCycling; - _vm->boundaryCollision(obj); // Must have got hero! + boundaryCollision(obj); // Must have got hero! } obj->oldvx = obj->vx; obj->oldvy = obj->vy; @@ -277,7 +277,7 @@ void ObjectHandler_v1w::moveObjects() { } // Store boundaries if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); + storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); } } @@ -297,25 +297,25 @@ void ObjectHandler_v1w::moveObjects() { int y2 = obj->y + currImage->y2; // Bottom edge if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->clearBoundary(x1, x2, y2); // Clear our own boundary + clearBoundary(x1, x2, y2); // Clear our own boundary // Allowable motion wrt boundary - int dx = _vm->deltaX(x1, x2, obj->vx, y2); + int dx = deltaX(x1, x2, obj->vx, y2); if (dx != obj->vx) { // An object boundary collision! - _vm->boundaryCollision(obj); + boundaryCollision(obj); obj->vx = 0; } - int dy = _vm->deltaY(x1, x2, obj->vy, y2); + int dy = deltaY(x1, x2, obj->vy, y2); if (dy != obj->vy) { // An object boundary collision! - _vm->boundaryCollision(obj); + boundaryCollision(obj); obj->vy = 0; } if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->storeBoundary(x1, x2, y2); // Re-store our own boundary + storeBoundary(x1, x2, y2); // Re-store our own boundary obj->x += dx; // Update object position obj->y += dy; @@ -340,7 +340,7 @@ void ObjectHandler_v1w::moveObjects() { object_t *obj = &_objects[i]; // Get pointer to object seq_t *currImage = obj->currImagePtr; // Get ptr to current image if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); + clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); } // If maze mode is enabled, do special maze processing diff --git a/engines/hugo/object_v2d.cpp b/engines/hugo/object_v2d.cpp index 17adae846a..7a4e5ce9a2 100644 --- a/engines/hugo/object_v2d.cpp +++ b/engines/hugo/object_v2d.cpp @@ -239,7 +239,7 @@ void ObjectHandler_v2d::moveObjects() { obj->cycling = kCycleForward; } else { obj->cycling = kCycleNotCycling; - _vm->boundaryCollision(obj); // Must have got hero! + boundaryCollision(obj); // Must have got hero! } obj->oldvx = obj->vx; obj->oldvy = obj->vy; @@ -280,7 +280,7 @@ void ObjectHandler_v2d::moveObjects() { } // Store boundaries if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); + storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); } } @@ -300,25 +300,25 @@ void ObjectHandler_v2d::moveObjects() { int y2 = obj->y + currImage->y2; // Bottom edge if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->clearBoundary(x1, x2, y2); // Clear our own boundary + clearBoundary(x1, x2, y2); // Clear our own boundary // Allowable motion wrt boundary - int dx = _vm->deltaX(x1, x2, obj->vx, y2); + int dx = deltaX(x1, x2, obj->vx, y2); if (dx != obj->vx) { // An object boundary collision! - _vm->boundaryCollision(obj); + boundaryCollision(obj); obj->vx = 0; } - int dy = _vm->deltaY(x1, x2, obj->vy, y2); + int dy = deltaY(x1, x2, obj->vy, y2); if (dy != obj->vy) { // An object boundary collision! - _vm->boundaryCollision(obj); + boundaryCollision(obj); obj->vy = 0; } if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->storeBoundary(x1, x2, y2); // Re-store our own boundary + storeBoundary(x1, x2, y2); // Re-store our own boundary obj->x += dx; // Update object position obj->y += dy; @@ -343,7 +343,7 @@ void ObjectHandler_v2d::moveObjects() { object_t *obj = &_objects[i]; // Get pointer to object seq_t *currImage = obj->currImagePtr; // Get ptr to current image if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); + clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); } // If maze mode is enabled, do special maze processing diff --git a/engines/hugo/object_v3d.cpp b/engines/hugo/object_v3d.cpp index e80a18bd5a..b9d7bcc261 100644 --- a/engines/hugo/object_v3d.cpp +++ b/engines/hugo/object_v3d.cpp @@ -120,7 +120,7 @@ void ObjectHandler_v3d::moveObjects() { obj->cycling = kCycleForward; } else { obj->cycling = kCycleNotCycling; - _vm->boundaryCollision(obj); // Must have got hero! + boundaryCollision(obj); // Must have got hero! } obj->oldvx = obj->vx; obj->oldvy = obj->vy; @@ -162,7 +162,7 @@ void ObjectHandler_v3d::moveObjects() { } // Store boundaries if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); + storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); } } @@ -182,25 +182,25 @@ void ObjectHandler_v3d::moveObjects() { int y2 = obj->y + currImage->y2; // Bottom edge if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->clearBoundary(x1, x2, y2); // Clear our own boundary + clearBoundary(x1, x2, y2); // Clear our own boundary // Allowable motion wrt boundary - int dx = _vm->deltaX(x1, x2, obj->vx, y2); + int dx = deltaX(x1, x2, obj->vx, y2); if (dx != obj->vx) { // An object boundary collision! - _vm->boundaryCollision(obj); + boundaryCollision(obj); obj->vx = 0; } - int dy = _vm->deltaY(x1, x2, obj->vy, y2); + int dy = deltaY(x1, x2, obj->vy, y2); if (dy != obj->vy) { // An object boundary collision! - _vm->boundaryCollision(obj); + boundaryCollision(obj); obj->vy = 0; } if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->storeBoundary(x1, x2, y2); // Re-store our own boundary + storeBoundary(x1, x2, y2); // Re-store our own boundary obj->x += dx; // Update object position obj->y += dy; @@ -225,7 +225,7 @@ void ObjectHandler_v3d::moveObjects() { object_t *obj = &_objects[i]; // Get pointer to object seq_t *currImage = obj->currImagePtr; // Get ptr to current image if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - _vm->clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); + clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); } // If maze mode is enabled, do special maze processing diff --git a/engines/hugo/route.cpp b/engines/hugo/route.cpp index 5f86591512..ad74acf4bf 100644 --- a/engines/hugo/route.cpp +++ b/engines/hugo/route.cpp @@ -329,21 +329,22 @@ bool Route::findRoute(const int16 cx, const int16 cy) { int i; for (i = 1, obj = &_vm->_object->_objects[i]; i < _vm->_object->_numObj; i++, obj++) { if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling != kCycleInvisible) && (obj->priority == kPriorityFloating)) - _vm->storeBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2); + _vm->_object->storeBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2); } // Combine objbound and boundary bitmaps to local byte map - for (int16 y = 0; y < kYPix; y++) { - for (int16 x = 0; x < kCompLineSize; x++) { + for (uint16 y = 0; y < kYPix; y++) { + for (uint16 x = 0; x < kCompLineSize; x++) { + uint16 boundIdx = y * kCompLineSize + x; for (i = 0; i < 8; i++) - _boundaryMap[y][x * 8 + i] = ((_vm->getObjectBoundaryOverlay()[y * kCompLineSize + x] | _vm->getBoundaryOverlay()[y * kCompLineSize + x]) & (0x80 >> i)) ? kMapBound : 0; + _boundaryMap[y][x * 8 + i] = ((_vm->_object->getObjectBoundary(boundIdx) | _vm->_object->getBoundaryOverlay(boundIdx)) & (0x80 >> i)) ? kMapBound : 0; } } // Clear all object baselines from objbound for (i = 0, obj = _vm->_object->_objects; i < _vm->_object->_numObj; i++, obj++) { if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling != kCycleInvisible) && (obj->priority == kPriorityFloating)) - _vm->clearBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2); + _vm->_object->clearBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2); } // Search from hero to destination diff --git a/engines/hugo/route.h b/engines/hugo/route.h index f9c80642db..ca5d03d910 100644 --- a/engines/hugo/route.h +++ b/engines/hugo/route.h @@ -35,6 +35,11 @@ namespace Hugo { +/** +* Purpose of an automatic route +*/ +enum go_t {kRouteSpace, kRouteExit, kRouteLook, kRouteGet}; + struct Point { int x; int y; @@ -49,8 +54,8 @@ class Route { public: Route(HugoEngine *vm); - void resetRoute() {_routeIndex = -1; } - int16 getRouteIndex() {return _routeIndex; } + void resetRoute() {_routeIndex = -1; } + int16 getRouteIndex() const {return _routeIndex; } void processRoute(); bool startRoute(const go_t go_for, const int16 id, int16 cx, int16 cy); -- cgit v1.2.3