diff options
Diffstat (limited to 'engines/agi/checks.cpp')
-rw-r--r-- | engines/agi/checks.cpp | 343 |
1 files changed, 178 insertions, 165 deletions
diff --git a/engines/agi/checks.cpp b/engines/agi/checks.cpp index e61146e901..1e1670f674 100644 --- a/engines/agi/checks.cpp +++ b/engines/agi/checks.cpp @@ -21,159 +21,153 @@ */ #include "agi/agi.h" +#include "agi/graphics.h" namespace Agi { -int AgiEngine::checkPosition(VtEntry *v) { - debugC(4, kDebugLevelSprites, "check position @ %d, %d", v->xPos, v->yPos); - - if (v->xPos < 0 || - v->xPos + v->xSize > _WIDTH || - v->yPos - v->ySize + 1 < 0 || - v->yPos >= _HEIGHT || - ((~v->flags & fIgnoreHorizon) && v->yPos <= _game.horizon)) { - debugC(4, kDebugLevelSprites, "check position failed: x=%d, y=%d, h=%d, w=%d", - v->xPos, v->yPos, v->xSize, v->ySize); - return 0; +bool AgiEngine::checkPosition(ScreenObjEntry *screenObj) { + bool result = true; // position is fine + debugC(4, kDebugLevelSprites, "check position @ %d, %d", screenObj->xPos, screenObj->yPos); + + if (screenObj->xPos < 0) { + result = false; + } else { + if (screenObj->xPos + screenObj->xSize > SCRIPT_WIDTH) { + result = false; + } else { + if (screenObj->yPos - screenObj->ySize < -1) { + result = false; + } else { + if (screenObj->yPos >= SCRIPT_HEIGHT) { + result = false; + } else { + if (((!(screenObj->flags & fIgnoreHorizon)) && screenObj->yPos <= _game.horizon)) { + result = false; + } + } + } + } } // MH1 needs this, but it breaks LSL1 - if (getVersion() >= 0x3000) { - if (v->yPos < v->ySize) - return 0; - } +// TODO: *NOT* in disassembly of AGI3 .149, why was this needed? +// if (getVersion() >= 0x3000) { +// if (screenObj->yPos < screenObj->ySize) +// result = false; +// } - return 1; + if (!result) { + debugC(4, kDebugLevelSprites, "check position failed: x=%d, y=%d, h=%d, w=%d", + screenObj->xPos, screenObj->yPos, screenObj->xSize, screenObj->ySize); + } + return result; } /** * Check if there's another object on the way */ -int AgiEngine::checkCollision(VtEntry *v) { - VtEntry *u; +bool AgiEngine::checkCollision(ScreenObjEntry *screenObj) { + ScreenObjEntry *checkObj; - if (v->flags & fIgnoreObjects) - return 0; + if (screenObj->flags & fIgnoreObjects) + return false; - for (u = _game.viewTable; u < &_game.viewTable[MAX_VIEWTABLE]; u++) { - if ((u->flags & (fAnimated | fDrawn)) != (fAnimated | fDrawn)) + for (checkObj = _game.screenObjTable; checkObj < &_game.screenObjTable[SCREENOBJECTS_MAX]; checkObj++) { + if ((checkObj->flags & (fAnimated | fDrawn)) != (fAnimated | fDrawn)) continue; - if (u->flags & fIgnoreObjects) + if (checkObj->flags & fIgnoreObjects) continue; // Same object, check next - if (v->entry == u->entry) + if (screenObj->objectNr == checkObj->objectNr) continue; // No horizontal overlap, check next - if (v->xPos + v->xSize < u->xPos || v->xPos > u->xPos + u->xSize) + if (screenObj->xPos + screenObj->xSize < checkObj->xPos || screenObj->xPos > checkObj->xPos + checkObj->xSize) continue; // Same y, return error! - if (v->yPos == u->yPos) { - debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", v->entry); - return 1; + if (screenObj->yPos == checkObj->yPos) { + debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", screenObj->objectNr); + return true; } // Crossed the baseline, return error! - if ((v->yPos > u->yPos && v->yPos2 < u->yPos2) || - (v->yPos < u->yPos && v->yPos2 > u->yPos2)) { - debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", v->entry); - return 1; + if ((screenObj->yPos > checkObj->yPos && screenObj->yPos_prev < checkObj->yPos_prev) || + (screenObj->yPos < checkObj->yPos && screenObj->yPos_prev > checkObj->yPos_prev)) { + debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", screenObj->objectNr); + return true; } } - return 0; - + return false; } -int AgiEngine::checkPriority(VtEntry *v) { - int i, trigger, water, pass, pri; - uint8 *p0; +bool AgiEngine::checkPriority(ScreenObjEntry *screenObj) { + bool touchedWater = false; + bool touchedTrigger = false; + bool touchedControl = true; + int16 curX; + int16 curY; + int16 celX; + byte screenPriority = 0; - if (~v->flags & fFixedPriority) { + if (!(screenObj->flags & fFixedPriority)) { // Priority bands - v->priority = _game.priTable[v->yPos]; + screenObj->priority = _gfx->priorityFromY(screenObj->yPos); } - trigger = 0; - water = 0; - pass = 1; + if (screenObj->priority != 0x0f) { - if (v->priority == 0x0f) { - // Check ego - if (v->entry == 0) { - setflag(fEgoTouchedP2, trigger ? true : false); - setflag(fEgoWater, water ? true : false); - } - - return pass; - } - - water = 1; - - // Check if any picture is loaded before checking for priority below. - // If no picture has been loaded, the priority buffer won't be initialized, - // thus the check below will always fail. This case causes an infinite loop - // in the fanmade game Nick's Quest (bug #3451122), as the game attempts to - // draw a sprite (view 4, floating Nick) before it loads any picture. This - // causes the checks below to always fail, and the engine keeps readjusting - // the sprite's position in fixPosition() forever, as there is no valid - // position to place it (the default visual and priority screen is set to - // zero, i.e. unconditional black). To remedy this situation, we always - // return true here if no picture has been loaded and no priority screen - // has been set up. - if (!_game._vm->_picture->isPictureLoaded()) { - warning("checkPriority: no picture loaded"); - return pass; - } - - p0 = &_game.sbuf16c[v->xPos + v->yPos * _WIDTH]; - - for (i = 0; i < v->xSize; i++, p0++) { - pri = *p0 >> 4; - - if (pri == 0) { // unconditional black. no go at all! - pass = 0; - break; - } + touchedWater = true; - if (pri == 3) // water surface - continue; + curX = screenObj->xPos; + curY = screenObj->yPos; - water = 0; + for (celX = 0; celX < screenObj->xSize; celX++, curX++) { + screenPriority = _gfx->getPriority(curX, curY); - if (pri == 1) { // conditional blue - if (v->flags & fIgnoreBlocks) - continue; + if (screenPriority == 0) { // unconditional black. no go at all! + touchedControl = 0; + break; + } - debugC(4, kDebugLevelSprites, "Blocks observed!"); - pass = 0; - break; + if (screenPriority != 3) { // not water surface + touchedWater = false; + + if (screenPriority == 1) { // conditional blue + if (!(screenObj->flags & fIgnoreBlocks)) { + debugC(4, kDebugLevelSprites, "Blocks observed!"); + touchedControl = false; + break; + } + } else if (screenPriority == 2) { + debugC(4, kDebugLevelSprites, "stepped on trigger"); + if (!_debug.ignoretriggers) + touchedTrigger = true; + } + } } - if (pri == 2) { // trigger - debugC(4, kDebugLevelSprites, "stepped on trigger"); - if (!_debug.ignoretriggers) - trigger = 1; + if (touchedControl) { + if (!touchedWater) { + if (screenObj->flags & fOnWater) + touchedControl = false; + } else { + if (screenObj->flags & fOnLand) + touchedControl = false; + } } } - if (pass) { - if (!water && v->flags & fOnWater) - pass = 0; - if (water && v->flags & fOnLand) - pass = 0; - } - // Check ego - if (v->entry == 0) { - setflag(fEgoTouchedP2, trigger ? true : false); - setflag(fEgoWater, water ? true : false); + if (screenObj->objectNr == 0) { + setFlag(VM_FLAG_EGO_TOUCHED_P2, touchedTrigger ? true : false); + setFlag(VM_FLAG_EGO_WATER, touchedWater ? true : false); } - return pass; + return touchedControl; } /* @@ -188,91 +182,106 @@ int AgiEngine::checkPriority(VtEntry *v) { * rules, otherwise the previous position will be kept. */ void AgiEngine::updatePosition() { - VtEntry *v; + ScreenObjEntry *screenObj; int x, y, oldX, oldY, border; - _game.vars[vBorderCode] = 0; - _game.vars[vBorderTouchEgo] = 0; - _game.vars[vBorderTouchObj] = 0; + setVar(VM_VAR_BORDER_CODE, 0); + setVar(VM_VAR_BORDER_TOUCH_EGO, 0); + setVar(VM_VAR_BORDER_TOUCH_OBJECT, 0); - for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) { - if ((v->flags & (fAnimated | fUpdate | fDrawn)) != (fAnimated | fUpdate | fDrawn)) { + for (screenObj = _game.screenObjTable; screenObj < &_game.screenObjTable[SCREENOBJECTS_MAX]; screenObj++) { + if ((screenObj->flags & (fAnimated | fUpdate | fDrawn)) != (fAnimated | fUpdate | fDrawn)) { continue; } - if (v->stepTimeCount != 0) { - if (--v->stepTimeCount != 0) - continue; + if (screenObj->stepTimeCount > 1) { + screenObj->stepTimeCount--; + continue; } - v->stepTimeCount = v->stepTime; + screenObj->stepTimeCount = screenObj->stepTime; - x = oldX = v->xPos; - y = oldY = v->yPos; + x = oldX = screenObj->xPos; + y = oldY = screenObj->yPos; // If object has moved, update its position - if (~v->flags & fUpdatePos) { + if (!(screenObj->flags & fUpdatePos)) { int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 }; int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 }; - x += v->stepSize * dx[v->direction]; - y += v->stepSize * dy[v->direction]; + x += screenObj->stepSize * dx[screenObj->direction]; + y += screenObj->stepSize * dy[screenObj->direction]; } // Now check if it touched the borders border = 0; // Check left/right borders - if (x < 0) { - x = 0; - border = 4; - } else if (x <= 0 && getVersion() == 0x3086) { // KQ4 - x = 0; // See Sarien bug #590462 - border = 4; - } else if (v->entry == 0 && x == 0 && v->flags & fAdjEgoXY) { - // Extra test to walk west clicking the mouse - x = 0; - border = 4; - } else if (x + v->xSize > _WIDTH) { - x = _WIDTH - v->xSize; - border = 2; + if (getVersion() == 0x3086) { + // KQ4 interpreter does a different comparison on x + // The interpreter before (2.917) and after that (3.098) don't do them that way + // This difference is required for at least Sarien bug #192 + // KQ4: room 135, hen moves from the center of the screen to the left border, + // but it doesn't disappear. + if (x <= 0) { + x = 0; + border = 4; + } + } else { + // regular comparison + if (x < 0) { + x = 0; + border = 4; + } + } + +// } else if (v->entry == 0 && x == 0 && v->flags & fAdjEgoXY) { // should not be required +// // Extra test to walk west clicking the mouse +// x = 0; +// border = 4; + + if (!border) { + if (x + screenObj->xSize > SCRIPT_WIDTH) { + x = SCRIPT_WIDTH - screenObj->xSize; + border = 2; + } } // Check top/bottom borders. - if (y - v->ySize + 1 < 0) { - y = v->ySize - 1; + if (y - screenObj->ySize < -1) { + y = screenObj->ySize - 1; border = 1; - } else if (y > _HEIGHT - 1) { - y = _HEIGHT - 1; + } else if (y > SCRIPT_HEIGHT - 1) { + y = SCRIPT_HEIGHT - 1; border = 3; - } else if ((~v->flags & fIgnoreHorizon) && y <= _game.horizon) { + } else if ((!(screenObj->flags & fIgnoreHorizon)) && y <= _game.horizon) { debugC(4, kDebugLevelSprites, "y = %d, horizon = %d", y, _game.horizon); y = _game.horizon + 1; border = 1; } // Test new position. rollback if test fails - v->xPos = x; - v->yPos = y; - if (checkCollision(v) || !checkPriority(v)) { - v->xPos = oldX; - v->yPos = oldY; + screenObj->xPos = x; + screenObj->yPos = y; + if (checkCollision(screenObj) || !checkPriority(screenObj)) { + screenObj->xPos = oldX; + screenObj->yPos = oldY; border = 0; - fixPosition(v->entry); + fixPosition(screenObj->objectNr); } - if (border != 0) { - if (isEgoView(v)) { - _game.vars[vBorderTouchEgo] = border; + if (border) { + if (isEgoView(screenObj)) { + setVar(VM_VAR_BORDER_TOUCH_EGO, border); } else { - _game.vars[vBorderCode] = v->entry; - _game.vars[vBorderTouchObj] = border; + setVar(VM_VAR_BORDER_CODE, screenObj->objectNr); + setVar(VM_VAR_BORDER_TOUCH_OBJECT, border); } - if (v->motion == kMotionMoveObj) { - inDestination(v); + if (screenObj->motionType == kMotionMoveObj) { + motionMoveObjStop(screenObj); } } - v->flags &= ~fUpdatePos; + screenObj->flags &= ~fUpdatePos; } } @@ -285,42 +294,46 @@ void AgiEngine::updatePosition() { * * @param n view table entry number */ -void AgiEngine::fixPosition(int n) { - VtEntry *v = &_game.viewTable[n]; +void AgiEngine::fixPosition(int16 screenObjNr) { + ScreenObjEntry *screenObj = &_game.screenObjTable[screenObjNr]; + fixPosition(screenObj); +} + +void AgiEngine::fixPosition(ScreenObjEntry *screenObj) { int count, dir, size; - debugC(4, kDebugLevelSprites, "adjusting view table entry #%d (%d,%d)", n, v->xPos, v->yPos); + debugC(4, kDebugLevelSprites, "adjusting view table entry #%d (%d,%d)", screenObj->objectNr, screenObj->xPos, screenObj->yPos); // test horizon - if ((~v->flags & fIgnoreHorizon) && v->yPos <= _game.horizon) - v->yPos = _game.horizon + 1; + if ((!(screenObj->flags & fIgnoreHorizon)) && screenObj->yPos <= _game.horizon) + screenObj->yPos = _game.horizon + 1; dir = 0; count = size = 1; - while (!checkPosition(v) || checkCollision(v) || !checkPriority(v)) { + while (!checkPosition(screenObj) || checkCollision(screenObj) || !checkPriority(screenObj)) { switch (dir) { - case 0: // west - v->xPos--; + case 0: // west + screenObj->xPos--; if (--count) continue; dir = 1; break; - case 1: // south - v->yPos++; + case 1: // south + screenObj->yPos++; if (--count) continue; dir = 2; size++; break; - case 2: // east - v->xPos++; + case 2: // east + screenObj->xPos++; if (--count) continue; dir = 3; break; - case 3: // north - v->yPos--; + case 3: // north + screenObj->yPos--; if (--count) continue; dir = 0; @@ -331,7 +344,7 @@ void AgiEngine::fixPosition(int n) { count = size; } - debugC(4, kDebugLevelSprites, "view table entry #%d position adjusted to (%d,%d)", n, v->xPos, v->yPos); + debugC(4, kDebugLevelSprites, "view table entry #%d position adjusted to (%d,%d)", screenObj->objectNr, screenObj->xPos, screenObj->yPos); } } // End of namespace Agi |