aboutsummaryrefslogtreecommitdiff
path: root/engines/agi/checks.cpp
diff options
context:
space:
mode:
authorMartin Kiewitz2016-01-29 13:13:40 +0100
committerMartin Kiewitz2016-01-29 13:22:22 +0100
commit8a595e7771aa89d06876e13d7ab6751e26da8982 (patch)
treedfc61e112c9f7e5b1d9e295fbb60edf4ae1b65f3 /engines/agi/checks.cpp
parent1e73796bd0b17740ca4c35b9a7bd1882f9de6a37 (diff)
downloadscummvm-rg350-8a595e7771aa89d06876e13d7ab6751e26da8982.tar.gz
scummvm-rg350-8a595e7771aa89d06876e13d7ab6751e26da8982.tar.bz2
scummvm-rg350-8a595e7771aa89d06876e13d7ab6751e26da8982.zip
AGI: graphics rewrite + cleanup
- graphics code fully rewritten - Apple IIgs font support - Amiga Topaz support - Word parser rewritten - menu code rewritten - removed forced 2 second delay on all room changes replaced with heuristic to detect situations, where it's required - lots of naming cleanup - new console commands show_map, screenobj, vmvars and vmflags - all sorts of hacks/workarounds removed - added SCI wait mouse cursor - added Apple IIgs mouse cursor - added Atari ST mouse cursor - added Amiga/Apple IIgs transition - added Atari ST transition - user can select another render mode and use Apple IIgs palette + transition for PC versions - inventory screen rewritten - SetSimple command now properly implemented - PreAGI Mickey: Sierra logo now shown - saved games: now saving controller key mapping also saving automatic save data (SetSimple command) - fixed invalid memory access when saving games (31 bytes were saved using Common::String c_ptr() Special Thanks to: - fuzzie for helping out with the Apple IIgs font + valgrind - eriktorbjorn for helping out with valgrind - LordHoto for figuring out the code, that caused invalid memory access in the original code, when saving a game - sev for help out with reversing the Amiga transition currently missing: - mouse support for menu - mouse support for system dialogs - predictive dialog support
Diffstat (limited to 'engines/agi/checks.cpp')
-rw-r--r--engines/agi/checks.cpp340
1 files changed, 178 insertions, 162 deletions
diff --git a/engines/agi/checks.cpp b/engines/agi/checks.cpp
index e61146e901..8399c9834a 100644
--- a/engines/agi/checks.cpp
+++ b/engines/agi/checks.cpp
@@ -21,159 +21,156 @@
*/
#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);
+bool AgiEngine::checkPosition(ScreenObjEntry *screenObj) {
+ bool result = true; // position is fine
+ debugC(4, kDebugLevelSprites, "check position @ %d, %d", screenObj->xPos, screenObj->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;
- }
+ do {
+ if (screenObj->xPos < 0) {
+ result = false;
+ break;
+ }
+ if (screenObj->xPos + screenObj->xSize > SCRIPT_WIDTH) {
+ result = false;
+ break;
+ }
+ if (screenObj->yPos - screenObj->ySize < -1) {
+ result = false;
+ break;
+ }
+ if (screenObj->yPos >= SCRIPT_HEIGHT) {
+ result = false;
+ break;
+ }
+ if (((!(screenObj->flags & fIgnoreHorizon)) && screenObj->yPos <= _game.horizon)) {
+ result = false;
+ break;
+ }
+ } while (0);
// 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];
- }
-
- trigger = 0;
- water = 0;
- pass = 1;
-
- 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;
+ screenObj->priority = _gfx->priorityFromY(screenObj->yPos);
}
- p0 = &_game.sbuf16c[v->xPos + v->yPos * _WIDTH];
-
- for (i = 0; i < v->xSize; i++, p0++) {
- pri = *p0 >> 4;
+ if (screenObj->priority != 0x0f) {
- 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 +185,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;
+ _game.vars[VM_VAR_BORDER_CODE] = 0;
+ _game.vars[VM_VAR_BORDER_TOUCH_EGO] = 0;
+ _game.vars[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)) {
+ _game.vars[VM_VAR_BORDER_TOUCH_EGO] = border;
} else {
- _game.vars[vBorderCode] = v->entry;
- _game.vars[vBorderTouchObj] = border;
+ _game.vars[VM_VAR_BORDER_CODE] = screenObj->objectNr;
+ _game.vars[VM_VAR_BORDER_TOUCH_OBJECT] = border;
}
- if (v->motion == kMotionMoveObj) {
- inDestination(v);
+ if (screenObj->motionType == kMotionMoveObj) { // ANGEPASST
+ motionMoveObjStop(screenObj);
}
}
- v->flags &= ~fUpdatePos;
+ screenObj->flags &= ~fUpdatePos;
}
}
@@ -285,42 +297,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--;
+ screenObj->xPos--;
if (--count)
continue;
dir = 1;
break;
case 1: // south
- v->yPos++;
+ screenObj->yPos++;
if (--count)
continue;
dir = 2;
size++;
break;
case 2: // east
- v->xPos++;
+ screenObj->xPos++;
if (--count)
continue;
dir = 3;
break;
case 3: // north
- v->yPos--;
+ screenObj->yPos--;
if (--count)
continue;
dir = 0;
@@ -331,7 +347,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