aboutsummaryrefslogtreecommitdiff
path: root/engines/hugo/object.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/hugo/object.cpp')
-rw-r--r--engines/hugo/object.cpp175
1 files changed, 174 insertions, 1 deletions
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