aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/gui32/gui32.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/gui32/gui32.cpp')
-rw-r--r--engines/sci/gui32/gui32.cpp136
1 files changed, 135 insertions, 1 deletions
diff --git a/engines/sci/gui32/gui32.cpp b/engines/sci/gui32/gui32.cpp
index c93c452b92..05627fa79c 100644
--- a/engines/sci/gui32/gui32.cpp
+++ b/engines/sci/gui32/gui32.cpp
@@ -739,7 +739,7 @@ void SciGui32::paletteAnimate(int fromColor, int toColor, int speed) {
//warning("STUB");
}
-int16 SciGui32::onControl(byte screenMask, Common::Rect rect) {
+uint16 SciGui32::onControl(byte screenMask, Common::Rect rect) {
gfx_map_mask_t map = (gfx_map_mask_t)screenMask;
rect_t gfxrect = gfx_rect(rect.left, rect.top + 10, rect.width(), rect.height());
@@ -2010,6 +2010,140 @@ void SciGui32::setNowSeen(reg_t objectReference) {
_k_set_now_seen(objectReference);
}
+static int collides_with(EngineState *s, Common::Rect area, reg_t other_obj, int use_nsrect, int view_mask) {
+ SegManager *segMan = s->_segMan;
+ int other_signal = GET_SEL32V(other_obj, signal);
+ int other_priority = GET_SEL32V(other_obj, priority);
+ int y = (int16)GET_SEL32V(other_obj, y);
+ Common::Rect other_area;
+
+ if (use_nsrect) {
+ other_area = get_nsrect(s, other_obj, 0);
+ other_area = nsrect_clip(s, y, other_area, other_priority);
+ } else {
+ other_area.left = GET_SEL32V(other_obj, brLeft);
+ other_area.right = GET_SEL32V(other_obj, brRight);
+ other_area.top = GET_SEL32V(other_obj, brTop);
+ other_area.bottom = GET_SEL32V(other_obj, brBottom);
+ }
+
+ if (other_area.right < 0 || other_area.bottom < 0 || area.right < 0 || area.bottom < 0)
+ return 0; // Out of scope
+
+ if (other_area.left >= 320 || other_area.top >= 190 || area.right >= 320 || area.bottom >= 190)
+ return 0; // Out of scope
+
+ debugC(2, kDebugLevelBresen, "OtherSignal=%04x, z=%04x obj=%04x:%04x\n", other_signal, (other_signal & view_mask), PRINT_REG(other_obj));
+
+ if ((other_signal & (view_mask)) == 0) {
+ // check whether the other object ignores actors
+
+ debugC(2, kDebugLevelBresen, " against (%d,%d) to (%d,%d)\n", other_area.left, other_area.top, other_area.right, other_area.bottom);
+
+ if (area.intersects(other_area))
+ return 1;
+ /* CR (from :Bob Heitman:) Collision rects have Mac semantics, ((0,0),(1,1)) only
+ ** covers the coordinate (0,0) */
+ }
+
+ debugC(2, kDebugLevelBresen, " (no)\n");
+ return 0;
+}
+
+#define GASEOUS_VIEW_MASK_ACTIVE (_K_VIEW_SIG_FLAG_REMOVE | _K_VIEW_SIG_FLAG_IGNORE_ACTOR)
+#define GASEOUS_VIEW_MASK_PASSIVE (_K_VIEW_SIG_FLAG_NO_UPDATE | _K_VIEW_SIG_FLAG_REMOVE | _K_VIEW_SIG_FLAG_IGNORE_ACTOR)
+
+bool SciGui32::canBeHere(reg_t curObject, reg_t listReference) {
+ SegManager *segMan = s->_segMan;
+ List *cliplist = NULL;
+ GfxPort *port = s->picture_port;
+ uint16 signal;
+ bool retval;
+
+ Common::Rect abs_zone;
+ rect_t zone;
+ uint16 edgehit;
+ uint16 illegal_bits;
+
+ abs_zone.left = (int16)GET_SEL32V(curObject, brLeft);
+ abs_zone.right = (int16)GET_SEL32V(curObject, brRight);
+ abs_zone.top = (int16)GET_SEL32V(curObject, brTop);
+ abs_zone.bottom = (int16)GET_SEL32V(curObject, brBottom);
+
+ zone = gfx_rect(abs_zone.left + port->zone.x, abs_zone.top + port->zone.y, abs_zone.width(), abs_zone.height());
+
+ signal = GET_SEL32V(curObject, signal);
+ debugC(2, kDebugLevelBresen, "Checking collision: (%d,%d) to (%d,%d) ([%d..%d]x[%d..%d]), obj=%04x:%04x, sig=%04x, cliplist=%04x:%04x\n",
+ GFX_PRINT_RECT(zone), abs_zone.left, abs_zone.right, abs_zone.top, abs_zone.bottom,
+ PRINT_REG(curObject), signal, PRINT_REG(listReference));
+
+ illegal_bits = GET_SEL32V(curObject, illegalBits);
+
+ retval = !(illegal_bits & (edgehit = gfxop_scan_bitmask(s->gfx_state, zone, GFX_MASK_CONTROL)));
+
+ debugC(2, kDebugLevelBresen, "edgehit = %04x (illegalBits %04x)\n", edgehit, illegal_bits);
+ if (!retval) {
+ debugC(2, kDebugLevelBresen, " -> %04x\n", retval);
+ return false; // Can't BeHere
+ }
+
+ retval = false;
+
+ if ((illegal_bits & 0x8000) // If we are vulnerable to those views at all...
+ && s->dyn_views) { // ...check against all stop-updated dynviews
+ GfxDynView *widget = (GfxDynView *)s->dyn_views->_contents;
+
+ debugC(2, kDebugLevelBresen, "Checking vs dynviews:\n");
+
+ while (widget) {
+ if (widget->_ID && (widget->signal & _K_VIEW_SIG_FLAG_STOPUPD)
+ && ((widget->_ID != curObject.segment) || (widget->_subID != curObject.offset))
+ && s->_segMan->isObject(make_reg(widget->_ID, widget->_subID)))
+ if (collides_with(s, abs_zone, make_reg(widget->_ID, widget->_subID), 1, GASEOUS_VIEW_MASK_ACTIVE))
+ return false;
+
+ widget = (GfxDynView *)widget->_next;
+ }
+ }
+
+ if (signal & GASEOUS_VIEW_MASK_ACTIVE) {
+ retval = (signal & GASEOUS_VIEW_MASK_ACTIVE) ? true : false; // CanBeHere- it's either being disposed, or it ignores actors anyway
+ debugC(2, kDebugLevelBresen, " -> %04x\n", retval);
+ return retval; // CanBeHere
+ }
+
+ if (listReference.segment)
+ cliplist = s->_segMan->lookupList(listReference);
+
+ if (cliplist) {
+ Node *node = s->_segMan->lookupNode(cliplist->first);
+
+ retval = false; // Assume that we Can'tBeHere...
+
+ while (node) { // Check each object in the list against our bounding rectangle
+ reg_t other_obj = node->value;
+ debugC(2, kDebugLevelBresen, " comparing against %04x:%04x\n", PRINT_REG(other_obj));
+
+ if (!s->_segMan->isObject(other_obj)) {
+ warning("CanBeHere() cliplist contains non-object %04x:%04x", PRINT_REG(other_obj));
+ } else if (other_obj != curObject) { // Clipping against yourself is not recommended
+
+ if (collides_with(s, abs_zone, other_obj, 0, GASEOUS_VIEW_MASK_PASSIVE)) {
+ debugC(2, kDebugLevelBresen, " -> %04x\n", retval);
+ return false;
+ }
+
+ } // if (other_obj != obj)
+ node = s->_segMan->lookupNode(node->succ); // move on
+ }
+ }
+
+ if (!retval)
+ retval = true;
+ debugC(2, kDebugLevelBresen, " -> %04x\n", retval);
+ return retval;
+}
+
void SciGui32::hideCursor() {
CursorMan.showMouse(false);
}