aboutsummaryrefslogtreecommitdiff
path: root/engines/agi/op_cmd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/agi/op_cmd.cpp')
-rw-r--r--engines/agi/op_cmd.cpp2422
1 files changed, 1494 insertions, 928 deletions
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 662454f3c1..8a62fce86c 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -23,55 +23,56 @@
#include "base/version.h"
#include "agi/agi.h"
+#include "agi/inv.h"
#include "agi/sprite.h"
+#include "agi/text.h"
#include "agi/graphics.h"
#include "agi/opcodes.h"
#include "agi/menu.h"
+#include "agi/systemui.h"
+#include "agi/words.h"
#include "common/random.h"
#include "common/textconsole.h"
namespace Agi {
-#define p0 (p[0])
-#define p1 (p[1])
-#define p2 (p[2])
-#define p3 (p[3])
-#define p4 (p[4])
-#define p5 (p[5])
-#define p6 (p[6])
-
-#define code state->_curLogic->data
-#define ip state->_curLogic->cIP
-#define vt state->viewTable[p0]
-#define vt_v state->viewTable[state->vars[p0]]
-
-#define _v state->vars
-
-#define getGameID() state->_vm->getGameID()
#define getFeatures() state->_vm->getFeatures()
#define getVersion() state->_vm->getVersion()
#define getLanguage() state->_vm->getLanguage()
-#define setflag(a,b) state->_vm->setflag(a,b)
-#define getflag(a) state->_vm->getflag(a)
-void cmdIncrement(AgiGame *state, uint8 *p) {
+void cmdIncrement(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte varVal = vm->getVar(varNr);
+
if (getVersion() < 0x2000) {
- if (_v[p0] < 0xf0)
- ++_v[p0];
+ if (varVal < 0xf0) {
+ varVal++;
+ vm->setVar(varNr, varVal);
+ }
} else {
- if (_v[p0] != 0xff)
- ++_v[p0];
+ if (varVal != 0xff) {
+ varVal++;
+ vm->setVar(varNr, varVal);
+ }
}
}
-void cmdDecrement(AgiGame *state, uint8 *p) {
- if (_v[p0] != 0)
- --_v[p0];
+void cmdDecrement(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte varVal = vm->getVar(varNr);
+
+ if (varVal != 0) {
+ varVal--;
+ vm->setVar(varNr, varVal);
+ }
}
-void cmdAssignN(AgiGame *state, uint8 *p) {
- _v[p0] = p1;
+void cmdAssignN(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 value = parameter[1];
+
+ vm->setVar(varNr, value);
// WORKAROUND for a bug in fan game "Get outta SQ"
// Total number of points is stored in variable 7, which
@@ -80,459 +81,725 @@ void cmdAssignN(AgiGame *state, uint8 *p) {
// variable to the correct value here
// Fixes bug #1942476 - "AGI: Fan(Get Outta SQ) - Score
// is lost on restart"
- if (getGameID() == GID_GETOUTTASQ && p0 == 7)
- _v[p0] = 8;
+ if (vm->getGameID() == GID_GETOUTTASQ && varNr == 7)
+ vm->setVar(varNr, 8);
}
-void cmdAddN(AgiGame *state, uint8 *p) {
- _v[p0] += p1;
+void cmdAddN(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 value = parameter[1];
+ byte varVal = vm->getVar(varNr);
+
+ vm->setVar(varNr, varVal + value);
}
-void cmdSubN(AgiGame *state, uint8 *p) {
- _v[p0] -= p1;
+void cmdSubN(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 value = parameter[1];
+ byte varVal = vm->getVar(varNr);
+
+ vm->setVar(varNr, varVal - value);
}
-void cmdAssignV(AgiGame *state, uint8 *p) {
- _v[p0] = _v[p1];
+void cmdAssignV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal2 = vm->getVar(varNr2);
+
+ vm->setVar(varNr1, varVal2);
}
-void cmdAddV(AgiGame *state, uint8 *p) {
- _v[p0] += _v[p1];
+void cmdAddV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+ byte varVal2 = vm->getVar(varNr2);
+
+ vm->setVar(varNr1, varVal1 + varVal2);
}
-void cmdSubV(AgiGame *state, uint8 *p) {
- _v[p0] -= _v[p1];
+void cmdSubV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+ byte varVal2 = vm->getVar(varNr2);
+
+ vm->setVar(varNr1, varVal1 - varVal2);
}
-void cmdMulN(AgiGame *state, uint8 *p) {
- _v[p0] *= p1;
+void cmdMulN(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 value = parameter[1];
+ byte varVal = vm->getVar(varNr);
+
+ vm->setVar(varNr, varVal * value);
}
-void cmdMulV(AgiGame *state, uint8 *p) {
- _v[p0] *= _v[p1];
+void cmdMulV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+ byte varVal2 = vm->getVar(varNr2);
+
+ vm->setVar(varNr1, varVal1 * varVal2);
}
-void cmdDivN(AgiGame *state, uint8 *p) {
- _v[p0] /= p1;
+void cmdDivN(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 value = parameter[1];
+ byte varVal = vm->getVar(varNr);
+
+ vm->setVar(varNr, varVal / value);
}
-void cmdDivV(AgiGame *state, uint8 *p) {
- _v[p0] /= _v[p1];
+void cmdDivV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+ byte varVal2 = vm->getVar(varNr2);
+
+ vm->setVar(varNr1, varVal1 / varVal2);
}
-void cmdRandomV1(AgiGame *state, uint8 *p) {
- _v[p0] = state->_vm->_rnd->getRandomNumber(250);
+void cmdRandomV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+
+ vm->setVar(varNr, vm->_rnd->getRandomNumber(250));
}
-void cmdRandom(AgiGame *state, uint8 *p) {
- _v[p2] = state->_vm->_rnd->getRandomNumber(p1 - p0) + p0;
+void cmdRandom(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 valueMin = parameter[0];
+ uint16 valueMax = parameter[1];
+ uint16 varNr = parameter[2];
+
+ vm->setVar(varNr, vm->_rnd->getRandomNumber(valueMax - valueMin) + valueMin);
}
-void cmdLindirectN(AgiGame *state, uint8 *p) {
- _v[_v[p0]] = p1;
+void cmdLindirectN(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 value = parameter[1];
+ byte varVal = vm->getVar(varNr);
+
+ vm->setVar(varVal, value);
}
-void cmdLindirectV(AgiGame *state, uint8 *p) {
- _v[_v[p0]] = _v[p1];
+void cmdLindirectV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+ byte varVal2 = vm->getVar(varNr2);
+
+ vm->setVar(varVal1, varVal2);
}
-void cmdRindirect(AgiGame *state, uint8 *p) {
- _v[p0] = _v[_v[p1]];
+void cmdRindirect(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal2 = vm->getVar(varNr2);
+ byte value = vm->getVar(varVal2);
+
+ vm->setVar(varNr1, value);
}
-void cmdSet(AgiGame *state, uint8 *p) {
- setflag(*p, true);
+void cmdSet(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 flagNr = parameter[0];
+
+ vm->setFlag(flagNr, true);
}
-void cmdReset(AgiGame *state, uint8 *p) {
- setflag(*p, false);
+void cmdReset(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 flagNr = parameter[0];
+
+ vm->setFlag(flagNr, false);
}
-void cmdToggle(AgiGame *state, uint8 *p) {
- setflag(*p, !getflag(*p));
+void cmdToggle(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 flagNr = parameter[0];
+ bool curFlagState = vm->getFlag(flagNr);
+
+ vm->setFlag(flagNr, !curFlagState);
}
-void cmdSetV(AgiGame *state, uint8 *p) {
+void cmdSetV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 flagNr = parameter[0];
+
if (getVersion() < 0x2000) {
- _v[p0] = 1;
+ vm->setVar(flagNr, 1);
} else {
- setflag(_v[p0], true);
+ flagNr = vm->getVar(flagNr);
+
+ vm->setFlag(flagNr, true);
}
}
-void cmdResetV(AgiGame *state, uint8 *p) {
+void cmdResetV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 flagNr = parameter[0];
+
if (getVersion() < 0x2000) {
- _v[p0] = 0;
+ vm->setVar(flagNr, 0);
} else {
- setflag(_v[p0], false);
+ flagNr = vm->getVar(flagNr);
+
+ vm->setFlag(flagNr, false);
}
}
-void cmdToggleV(AgiGame *state, uint8 *p) {
+void cmdToggleV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 flagNr = parameter[0];
+
if (getVersion() < 0x2000) {
- _v[p0] ^= 1;
+ byte value = vm->getVar(flagNr);
+ vm->setVar(flagNr, value ^ 1);
} else {
- setflag(_v[p0], !getflag(_v[p0]));
+ flagNr = vm->getVar(flagNr);
+ bool curFlagState = vm->getFlag(flagNr);
+
+ vm->setFlag(flagNr, !curFlagState);
}
}
-void cmdNewRoom(AgiGame *state, uint8 *p) {
- state->_vm->newRoom(p0);
+void cmdNewRoom(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 newRoomNr = parameter[0];
- // WORKAROUND: Works around intro skipping bug (#1737343) in Gold Rush.
- // Intro was skipped because the enter-keypress finalizing the entering
- // of the copy protection string (Copy protection is in logic.128) was
- // left over to the intro scene (Starts with room 73 i.e. logic.073).
- // The intro scene checks for any keys pressed and if it finds any it
- // jumps to the game's start (Room 1 i.e. logic.001). We clear the
- // keyboard buffer when the intro sequence's first room (Room 73) is
- // loaded so that no keys from the copy protection scene can be left
- // over to cause the intro to skip to the game's start.
- if (getGameID() == GID_GOLDRUSH && p0 == 73)
- state->keypress = 0;
+ state->_vm->newRoom(newRoomNr);
}
-void cmdNewRoomF(AgiGame *state, uint8 *p) {
- state->_vm->newRoom(_v[p0]);
+void cmdNewRoomF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte value = vm->getVar(varNr);
+
+ state->_vm->newRoom(value);
}
-void cmdLoadView(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rVIEW, p0);
+void cmdLoadView(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+
+ state->_vm->agiLoadResource(RESOURCETYPE_VIEW, resourceNr);
}
-void cmdLoadLogic(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rLOGIC, p0);
+void cmdLoadLogic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+
+ state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, resourceNr);
}
-void cmdLoadSound(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rSOUND, p0);
+void cmdLoadSound(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+
+ state->_vm->agiLoadResource(RESOURCETYPE_SOUND, resourceNr);
}
-void cmdLoadViewF(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rVIEW, _v[p0]);
+void cmdLoadViewF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte value = vm->getVar(varNr);
+
+ vm->agiLoadResource(RESOURCETYPE_VIEW, value);
}
-void cmdLoadLogicF(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rLOGIC, _v[p0]);
+void cmdLoadLogicF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte value = vm->getVar(varNr);
+
+ state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, value);
}
-void cmdDiscardView(AgiGame *state, uint8 *p) {
- state->_vm->agiUnloadResource(rVIEW, p0);
+void cmdDiscardView(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+
+ state->_vm->agiUnloadResource(RESOURCETYPE_VIEW, resourceNr);
}
-void cmdObjectOnAnything(AgiGame *state, uint8 *p) {
- vt.flags &= ~(fOnWater | fOnLand);
+void cmdObjectOnAnything(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~(fOnWater | fOnLand);
}
-void cmdObjectOnLand(AgiGame *state, uint8 *p) {
- vt.flags |= fOnLand;
+void cmdObjectOnLand(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fOnLand;
}
-void cmdObjectOnWater(AgiGame *state, uint8 *p) {
- vt.flags |= fOnWater;
+void cmdObjectOnWater(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fOnWater;
}
-void cmdObserveHorizon(AgiGame *state, uint8 *p) {
- vt.flags &= ~fIgnoreHorizon;
+void cmdObserveHorizon(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fIgnoreHorizon;
}
-void cmdIgnoreHorizon(AgiGame *state, uint8 *p) {
- vt.flags |= fIgnoreHorizon;
+void cmdIgnoreHorizon(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fIgnoreHorizon;
}
-void cmdObserveObjs(AgiGame *state, uint8 *p) {
- vt.flags &= ~fIgnoreObjects;
+void cmdObserveObjs(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fIgnoreObjects;
}
-void cmdIgnoreObjs(AgiGame *state, uint8 *p) {
- vt.flags |= fIgnoreObjects;
+void cmdIgnoreObjs(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fIgnoreObjects;
}
-void cmdObserveBlocks(AgiGame *state, uint8 *p) {
- vt.flags &= ~fIgnoreBlocks;
+void cmdObserveBlocks(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fIgnoreBlocks;
}
-void cmdIgnoreBlocks(AgiGame *state, uint8 *p) {
- vt.flags |= fIgnoreBlocks;
+void cmdIgnoreBlocks(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fIgnoreBlocks;
}
-void cmdSetHorizon(AgiGame *state, uint8 *p) {
- state->horizon = p0;
+void cmdSetHorizon(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 horizonValue = parameter[0];
+
+ state->horizon = horizonValue;
}
-void cmdGetPriority(AgiGame *state, uint8 *p) {
- _v[p1] = vt.priority;
+void cmdGetPriority(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->priority);
}
-void cmdSetPriority(AgiGame *state, uint8 *p) {
- vt.flags |= fFixedPriority;
- vt.priority = p1;
+void cmdSetPriority(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 priority = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- // WORKAROUND: this fixes bug #1712585 in KQ4 (dwarf sprite priority)
- // For this scene, ego (Rosella) hasn't got a fixed priority till script 54
- // explicitly sets priority 8 for her, so that she can walk back to the table
- // without being drawn over the other dwarfs
- // It seems that in this scene, ego's priority is set to 8, but the priority of
- // the last dwarf with the soup bowls (view 152) is also set to 8, which causes
- // the dwarf to be drawn behind ego
- // With this workaround, when the game scripts set the priority of view 152
- // (seventh dwarf with soup bowls), ego's priority is set to 7
- // The game script itself sets priotity 8 for ego before she starts walking,
- // and then releases the fixed priority set on ego after ego is seated
- // Therefore, this workaround only affects that specific part of this scene
- // Ego is set to object 19 by script 54
- if (getGameID() == GID_KQ4 && vt.currentView == 152) {
- state->viewTable[19].flags |= fFixedPriority;
- state->viewTable[19].priority = 7;
- }
+ screenObj->flags |= fFixedPriority;
+ screenObj->priority = priority;
}
-void cmdSetPriorityF(AgiGame *state, uint8 *p) {
- vt.flags |= fFixedPriority;
- vt.priority = _v[p1];
+void cmdSetPriorityF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fFixedPriority;
+ screenObj->priority = vm->getVar(varNr);
}
-void cmdReleasePriority(AgiGame *state, uint8 *p) {
- vt.flags &= ~fFixedPriority;
+void cmdReleasePriority(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fFixedPriority;
}
-void cmdSetUpperLeft(AgiGame *state, uint8 *p) { // do nothing (AGI 2.917)
+void cmdSetUpperLeft(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // do nothing (AGI 2.917)
}
-void cmdStartUpdate(AgiGame *state, uint8 *p) {
- state->_vm->startUpdate(&vt);
+void cmdStartUpdate(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ state->_vm->startUpdate(screenObj);
}
-void cmdStopUpdate(AgiGame *state, uint8 *p) {
- state->_vm->stopUpdate(&vt);
+void cmdStopUpdate(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ state->_vm->stopUpdate(screenObj);
}
-void cmdCurrentView(AgiGame *state, uint8 *p) {
- _v[p1] = vt.currentView;
+void cmdCurrentView(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->currentViewNr);
}
-void cmdCurrentCel(AgiGame *state, uint8 *p) {
- _v[p1] = vt.currentCel;
- debugC(4, kDebugLevelScripts, "v%d=%d", p1, _v[p1]);
+void cmdCurrentCel(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->currentCelNr);
+ debugC(4, kDebugLevelScripts, "v%d=%d", varNr, screenObj->currentCelNr);
}
-void cmdCurrentLoop(AgiGame *state, uint8 *p) {
- _v[p1] = vt.currentLoop;
+void cmdCurrentLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->currentLoopNr);
}
-void cmdLastCel(AgiGame *state, uint8 *p) {
- _v[p1] = vt.loopData->numCels - 1;
+void cmdLastCel(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->loopData->celCount - 1);
}
-void cmdSetCel(AgiGame *state, uint8 *p) {
- state->_vm->setCel(&vt, p1);
+void cmdSetCel(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 celNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+ vm->setCel(screenObj, celNr);
if (getVersion() >= 0x2000) {
- vt.flags &= ~fDontupdate;
+ screenObj->flags &= ~fDontupdate;
}
}
-void cmdSetCelF(AgiGame *state, uint8 *p) {
- state->_vm->setCel(&vt, _v[p1]);
- vt.flags &= ~fDontupdate;
+void cmdSetCelF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+ byte value = vm->getVar(varNr);
+
+ vm->setCel(screenObj, value);
+ screenObj->flags &= ~fDontupdate;
}
-void cmdSetView(AgiGame *state, uint8 *p) {
- state->_vm->setView(&vt, p1);
+void cmdSetView(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 viewNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ state->_vm->setView(screenObj, viewNr);
}
-void cmdSetViewF(AgiGame *state, uint8 *p) {
- state->_vm->setView(&vt, _v[p1]);
+void cmdSetViewF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+ byte value = vm->getVar(varNr);
+
+ state->_vm->setView(screenObj, value);
}
-void cmdSetLoop(AgiGame *state, uint8 *p) {
- state->_vm->setLoop(&vt, p1);
+void cmdSetLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 loopNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ state->_vm->setLoop(screenObj, loopNr);
}
-void cmdSetLoopF(AgiGame *state, uint8 *p) {
- state->_vm->setLoop(&vt, _v[p1]);
+void cmdSetLoopF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+ byte value = vm->getVar(varNr);
+
+ state->_vm->setLoop(screenObj, value);
}
-void cmdNumberOfLoops(AgiGame *state, uint8 *p) {
- _v[p1] = vt.numLoops;
+void cmdNumberOfLoops(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->loopCount);
}
-void cmdFixLoop(AgiGame *state, uint8 *p) {
- vt.flags |= fFixLoop;
+void cmdFixLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fFixLoop;
}
-void cmdReleaseLoop(AgiGame *state, uint8 *p) {
- vt.flags &= ~fFixLoop;
+void cmdReleaseLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fFixLoop;
}
-void cmdStepSize(AgiGame *state, uint8 *p) {
- vt.stepSize = _v[p1];
+void cmdStepSize(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->stepSize = vm->getVar(varNr);
}
-void cmdStepTime(AgiGame *state, uint8 *p) {
- vt.stepTime = vt.stepTimeCount = _v[p1];
+void cmdStepTime(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->stepTime = screenObj->stepTimeCount = vm->getVar(varNr);
}
-void cmdCycleTime(AgiGame *state, uint8 *p) {
- vt.cycleTime = vt.cycleTimeCount = _v[p1];
+void cmdCycleTime(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->cycleTime = screenObj->cycleTimeCount = vm->getVar(varNr);
}
-void cmdStopCycling(AgiGame *state, uint8 *p) {
- vt.flags &= ~fCycling;
+void cmdStopCycling(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fCycling;
}
-void cmdStartCycling(AgiGame *state, uint8 *p) {
- vt.flags |= fCycling;
+void cmdStartCycling(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fCycling;
}
-void cmdNormalCycle(AgiGame *state, uint8 *p) {
- vt.cycle = kCycleNormal;
- vt.flags |= fCycling;
+void cmdNormalCycle(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->cycle = kCycleNormal;
+ screenObj->flags |= fCycling;
}
-void cmdReverseCycle(AgiGame *state, uint8 *p) {
- vt.cycle = kCycleReverse;
- vt.flags |= fCycling;
+void cmdReverseCycle(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->cycle = kCycleReverse;
+ screenObj->flags |= fCycling;
}
-void cmdSetDir(AgiGame *state, uint8 *p) {
- vt.direction = _v[p1];
+void cmdSetDir(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->direction = vm->getVar(varNr);
}
-void cmdGetDir(AgiGame *state, uint8 *p) {
- _v[p1] = vt.direction;
+void cmdGetDir(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr, screenObj->direction);
}
-void cmdGetRoomF(AgiGame *state, uint8 *p) {
- _v[p1] = state->_vm->objectGetLocation(_v[p0]);
+void cmdGetRoomF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+
+ vm->setVar(varNr2, state->_vm->objectGetLocation(varVal1));
}
-void cmdPut(AgiGame *state, uint8 *p) {
- state->_vm->objectSetLocation(p0, _v[p1]);
+void cmdPut(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr = parameter[1];
+ byte varVal = vm->getVar(varNr);
+
+ vm->objectSetLocation(objectNr, varVal);
}
-void cmdPutF(AgiGame *state, uint8 *p) {
- state->_vm->objectSetLocation(_v[p0], _v[p1]);
+void cmdPutF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ byte varVal1 = vm->getVar(varNr1);
+ byte varVal2 = vm->getVar(varNr2);
+
+ state->_vm->objectSetLocation(varVal1, varVal2);
}
-void cmdDrop(AgiGame *state, uint8 *p) {
- state->_vm->objectSetLocation(p0, 0);
+void cmdDrop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+
+ state->_vm->objectSetLocation(objectNr, 0);
}
-void cmdGet(AgiGame *state, uint8 *p) {
- state->_vm->objectSetLocation(p0, EGO_OWNED);
+void cmdGet(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+
+ state->_vm->objectSetLocation(objectNr, EGO_OWNED);
}
-void cmdGetV1(AgiGame *state, uint8 *p) {
- state->_vm->objectSetLocation(p0, EGO_OWNED_V1);
+void cmdGetV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+
+ state->_vm->objectSetLocation(objectNr, EGO_OWNED_V1);
}
-void cmdGetF(AgiGame *state, uint8 *p) {
- state->_vm->objectSetLocation(_v[p0], EGO_OWNED);
+void cmdGetF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte varVal = vm->getVar(varNr);
+
+ state->_vm->objectSetLocation(varVal, EGO_OWNED);
}
-void cmdWordToString(AgiGame *state, uint8 *p) {
- strcpy(state->strings[p0], state->egoWords[p1].word);
+void cmdWordToString(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 stringNr = parameter[0];
+ uint16 wordNr = parameter[1];
+
+ Common::strlcpy(state->strings[stringNr], state->_vm->_words->getEgoWord(wordNr), MAX_STRINGLEN);
}
-void cmdOpenDialogue(AgiGame *state, uint8 *p) {
- state->hasWindow = true;
+void cmdOpenDialogue(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ vm->_text->dialogueOpen();
}
-void cmdCloseDialogue(AgiGame *state, uint8 *p) {
- state->hasWindow = false;
+void cmdCloseDialogue(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ vm->_text->dialogueClose();
}
-void cmdCloseWindow(AgiGame *state, uint8 *p) {
- state->_vm->closeWindow();
+void cmdCloseWindow(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ vm->_text->closeWindow();
}
-void cmdStatusLineOn(AgiGame *state, uint8 *p) {
- state->statusLine = true;
- state->_vm->writeStatus();
+void cmdStatusLineOn(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *text = state->_vm->_text;
+
+ text->statusEnable();
+ text->statusDraw();
}
-void cmdStatusLineOff(AgiGame *state, uint8 *p) {
- state->statusLine = false;
- state->_vm->writeStatus();
+void cmdStatusLineOff(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *text = state->_vm->_text;
+
+ text->statusDisable();
+ state->_vm->_text->statusClear();
}
-void cmdShowObj(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->showObj(p0);
+void cmdShowObj(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+
+ state->_vm->_sprites->showObject(objectNr);
}
-void cmdShowObjV(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->showObj(_v[p0]);
+void cmdShowObjV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte varVal = vm->getVar(varNr);
+
+ state->_vm->_sprites->showObject(varVal);
}
-void cmdSound(AgiGame *state, uint8 *p) {
- state->_vm->_sound->startSound(p0, p1);
+void cmdSound(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+ uint16 flagNr = parameter[1];
+
+ state->_vm->_sound->startSound(resourceNr, flagNr);
}
-void cmdStopSound(AgiGame *state, uint8 *p) {
+void cmdStopSound(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->_vm->_sound->stopSound();
}
-void cmdMenuInput(AgiGame *state, uint8 *p) {
- state->_vm->newInputMode(INPUT_MENU);
+void cmdMenuInput(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if (vm->getFlag(VM_FLAG_MENUS_ACCESSIBLE)) {
+ vm->_menu->delayedExecuteViaKeyboard();
+ }
}
-void cmdEnableItem(AgiGame *state, uint8 *p) {
- state->_vm->_menu->setItem(p0, true);
+void cmdEnableItem(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 controlCode = parameter[0];
+
+ state->_vm->_menu->itemEnable(controlCode);
}
-void cmdDisableItem(AgiGame *state, uint8 *p) {
- state->_vm->_menu->setItem(p0, false);
+void cmdDisableItem(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 controlCode = parameter[0];
+
+ state->_vm->_menu->itemDisable(controlCode);
}
-void cmdSubmitMenu(AgiGame *state, uint8 *p) {
+void cmdSubmitMenu(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->_vm->_menu->submit();
}
-void cmdSetScanStart(AgiGame *state, uint8 *p) {
+void cmdSetScanStart(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->_curLogic->sIP = state->_curLogic->cIP;
}
-void cmdResetScanStart(AgiGame *state, uint8 *p) {
+void cmdResetScanStart(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->_curLogic->sIP = 2;
}
-void cmdSaveGame(AgiGame *state, uint8 *p) {
- state->simpleSave ? state->_vm->saveGameSimple() : state->_vm->saveGameDialog();
-}
+void cmdSaveGame(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ vm->inGameTimerPause();
-void cmdLoadGame(AgiGame *state, uint8 *p) {
- assert(1);
- state->simpleSave ? state->_vm->loadGameSimple() : state->_vm->loadGameDialog();
+ if (state->automaticSave) {
+ if (vm->saveGameAutomatic()) {
+ // automatic save succeded
+ vm->inGameTimerResume();
+ return;
+ }
+ // fall back to regular dialog otherwise
+ }
+
+ vm->saveGameDialog();
+
+ vm->inGameTimerResume();
}
-void cmdInitDisk(AgiGame *state, uint8 *p) { // do nothing
+void cmdLoadGame(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ vm->inGameTimerPause();
+
+ if (state->automaticSave) {
+ if (vm->loadGameAutomatic()) {
+ // automatic restore succeded
+ vm->inGameTimerResume();
+ return;
+ }
+ // fall back to regular dialog otherwise
+ }
+
+ vm->loadGameDialog();
+
+ vm->inGameTimerResume();
}
-void cmdLog(AgiGame *state, uint8 *p) { // do nothing
+void cmdInitDisk(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // do nothing
}
-void cmdTraceOn(AgiGame *state, uint8 *p) { // do nothing
+void cmdLog(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // do nothing
}
-void cmdTraceInfo(AgiGame *state, uint8 *p) { // do nothing
+void cmdTraceOn(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // do nothing
}
-void cmdShowMem(AgiGame *state, uint8 *p) {
- state->_vm->messageBox("Enough memory");
+void cmdTraceInfo(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // do nothing
}
-void cmdInitJoy(AgiGame *state, uint8 *p) { // do nothing
+void cmdShowMem(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ state->_vm->_text->messageBox("Enough memory");
}
-void cmdScriptSize(AgiGame *state, uint8 *p) {
- debug(0, "script.size(%d)", p0);
+void cmdInitJoy(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // do nothing
}
-void cmdCancelLine(AgiGame *state, uint8 *p) {
- state->inputBuffer[0] = 0;
- state->cursorPos = 0;
- state->_vm->writePrompt();
+void cmdScriptSize(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ debug(0, "script.size(%d)", parameter[0]);
}
// This implementation is based on observations of Amiga's Gold Rush.
@@ -545,13 +812,16 @@ void cmdCancelLine(AgiGame *state, uint8 *p) {
// 4051 (When ego is stationary),
// 471 (When walking on the first screen's bridge),
// 71 (When walking around, using the mouse or the keyboard).
-void cmdObjStatusF(AgiGame *state, uint8 *p) {
+void cmdObjStatusF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[vm->getVar(varNr)];
+
const char *cycleDesc; // Object's cycle description line
const char *motionDesc; // Object's motion description line
char msg[256]; // The whole object status message
// Generate cycle description line
- switch (vt_v.cycle) {
+ switch (screenObj->cycle) {
case kCycleNormal:
cycleDesc = "normal cycle";
break;
@@ -570,7 +840,7 @@ void cmdObjStatusF(AgiGame *state, uint8 *p) {
}
// Generate motion description line
- switch (vt_v.motion) {
+ switch (screenObj->motionType) {
case kMotionNormal:
motionDesc = "normal motion";
break;
@@ -592,21 +862,21 @@ void cmdObjStatusF(AgiGame *state, uint8 *p) {
}
sprintf(msg,
- "Object %d:\n" \
- "x: %d xsize: %d\n" \
- "y: %d ysize: %d\n" \
- "pri: %d\n" \
- "stepsize: %d\n" \
- "%s\n" \
- "%s",
- _v[p0],
- vt_v.xPos, vt_v.xSize,
- vt_v.yPos, vt_v.ySize,
- vt_v.priority,
- vt_v.stepSize,
- cycleDesc,
- motionDesc);
- state->_vm->messageBox(msg);
+ "Object %d:\n" \
+ "x: %d xsize: %d\n" \
+ "y: %d ysize: %d\n" \
+ "pri: %d\n" \
+ "stepsize: %d\n" \
+ "%s\n" \
+ "%s",
+ vm->getVar(varNr),
+ screenObj->xPos, screenObj->xSize,
+ screenObj->yPos, screenObj->ySize,
+ screenObj->priority,
+ screenObj->stepSize,
+ cycleDesc,
+ motionDesc);
+ state->_vm->_text->messageBox(msg);
}
// unknown commands:
@@ -617,49 +887,105 @@ void cmdObjStatusF(AgiGame *state, uint8 *p) {
// unk_174: Change priority table (used in KQ4) -- j5
// unk_177: Disable menus completely -- j5
// unk_181: Deactivate keypressed control (default control of ego)
-void cmdSetSimple(AgiGame *state, uint8 *p) {
+void cmdSetSimple(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
if (!(getFeatures() & (GF_AGI256 | GF_AGI256_2))) {
- state->simpleSave = true;
+ // set.simple is called by Larry 1 on Apple IIgs at the store, after answering the 555-6969 phone.
+ // load.sound(16) is called right before it. Interpreter is 2.440-like.
+ // it's called with parameter 16.
+ // Original interpreter doesn't seem to play any sound.
+ // TODO: Figure out what's going on. It can't be automatic saving of course.
+ // Also getting called in KQ1, when planting beans - parameter 12.
+ // And when killing the witch - parameter 40.
+ if ((getVersion() < 0x2425) || (getVersion() == 0x2440)) {
+ // was not available before 2.2425, but also not available in 2.440
+ warning("set.simple called, although not available for current AGI version");
+ return;
+ }
+
+ int16 stringNr = parameter[0];
+ const char *textPtr = nullptr;
+
+ state->automaticSave = false;
+
+ // Try to get description for automatic saves
+ textPtr = state->strings[stringNr];
+
+ strncpy(state->automaticSaveDescription, textPtr, sizeof(state->automaticSaveDescription));
+ state->automaticSaveDescription[sizeof(state->automaticSaveDescription) - 1] = 0;
+
+ if (state->automaticSaveDescription[0]) {
+ // We got it and it's set, so enable automatic saving
+ state->automaticSave = true;
+ }
+
} else { // AGI256 and AGI256-2 use this unknown170 command to load 256 color pictures.
- // Load the picture. Similar to void cmdLoad_pic(AgiGame *state, uint8 *p).
- state->_vm->_sprites->eraseBoth();
- state->_vm->agiLoadResource(rPICTURE, _v[p0]);
-
- // Draw the picture. Similar to void cmdDraw_pic(AgiGame *state, uint8 *p).
- state->_vm->_picture->decodePicture(_v[p0], false, true);
- state->_vm->_sprites->blitBoth();
- state->pictureShown = 0;
-
- // Show the picture. Similar to void cmdShow_pic(AgiGame *state, uint8 *p).
- setflag(fOutputMode, false);
- state->_vm->closeWindow();
- state->_vm->_picture->showPic();
- state->pictureShown = 1;
-
- // Simulate slowww computer. Many effects rely on this
- state->_vm->pause(kPausePicture);
+ // Load the picture. Similar to void cmdLoad_pic(AgiGame *state, AgiEngine *vm, uint8 *p).
+ SpritesMgr *spritesMgr = state->_vm->_sprites;
+ uint16 varNr = parameter[0];
+ uint16 resourceNr = vm->getVar(varNr);
+
+ spritesMgr->eraseSprites();
+ vm->agiLoadResource(RESOURCETYPE_PICTURE, resourceNr);
+
+ // Draw the picture. Similar to void cmdDraw_pic(AgiGame *state, AgiEngine *vm, uint8 *p).
+ vm->_picture->decodePicture(resourceNr, false, true);
+ spritesMgr->drawAllSpriteLists();
+ state->pictureShown = false;
+
+ // Loading trigger
+ vm->artificialDelayTrigger_DrawPicture(resourceNr);
+
+ // Show the picture. Similar to void cmdShow_pic(AgiGame *state, AgiEngine *vm, uint8 *p).
+ vm->setFlag(VM_FLAG_OUTPUT_MODE, false);
+ vm->_text->closeWindow();
+ vm->_picture->showPic();
+ state->pictureShown = true;
}
}
-void cmdPopScript(AgiGame *state, uint8 *p) {
- if (getVersion() >= 0x2915) {
- debug(0, "pop.script");
+// push.script was not available until 2.425, and also not available in 2.440
+void cmdPopScript(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if ((getVersion() < 0x2425) || (getVersion() == 0x2440)) {
+ // was not available before 2.2425, but also not available in 2.440
+ warning("pop.script called, although not available for current AGI version");
+ return;
}
-}
-void cmdHoldKey(AgiGame *state, uint8 *p) {
- if (getVersion() >= 0x3098) {
- state->_vm->_egoHoldKey = true;
- }
+ debug(0, "pop.script");
}
-void cmdDiscardSound(AgiGame *state, uint8 *p) {
+void cmdDiscardSound(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
if (getVersion() >= 0x2936) {
debug(0, "discard.sound");
}
}
-void cmdHideMouse(AgiGame *state, uint8 *p) {
+void cmdShowMouse(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if (state->mouseEnabled) {
+ state->mouseHidden = false;
+
+ g_system->showMouse(true);
+ }
+}
+
+// Seems to have been added for AGI3, at least according to PC AGI
+// Space Quest 2 on Apple IIgs (using AGI ) calls it during the spaceship cutscene in the intro
+// but show.mouse is never called afterwards. Game running under emulator doesn't seem to hide the mouse cursor.
+// TODO: figure out, what exactly happens. Probably some hacked-in command and not related to mouse cursor for that game?
+void cmdHideMouse(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if (getVersion() < 0x3000) {
+ // was not available before 3.086
+ warning("hide.mouse, although not available for current AGI version");
+ return;
+ }
+
+ if ((vm->getGameID() == GID_MH1) && (vm->getPlatform() == Common::kPlatformApple2GS)) {
+ // Called right after beating arcade sequence on day 4 in the hospital Parameter is "1".
+ // Right before cutscene. show.mouse isn't called. Probably different function.
+ warning("hide.mouse called, disabled for MH1 Apple IIgs");
+ return;
+ }
+
// WORKAROUND: Turns off current movement that's being caused with the mouse.
// This fixes problems with too many popup boxes appearing in the Amiga
// Gold Rush's copy protection failure scene (i.e. the hanging scene, logic.192).
@@ -667,34 +993,64 @@ void cmdHideMouse(AgiGame *state, uint8 *p) {
// to walk somewhere else than to the right using the mouse.
// FIXME: Write a proper implementation using disassembly and
// apply it to other games as well if applicable.
- state->viewTable[0].flags &= ~fAdjEgoXY;
+ //state->screenObjTable[SCREENOBJECTS_EGO_ENTRY].flags &= ~fAdjEgoXY;
+ if (state->mouseEnabled) {
+ state->mouseHidden = true;
- g_system->showMouse(false);
+ g_system->showMouse(false);
+ }
}
-void cmdAllowMenu(AgiGame *state, uint8 *p) {
- if (getVersion() >= 0x3098) {
- setflag(fMenusWork, ((p0 != 0) ? true : false));
+void cmdAllowMenu(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if (getVersion() < 0x3098) {
+ // was not available before 3.098
+ warning("allow.menu called, although not available for current AGI version");
+ return;
+ }
+
+ uint16 allowed = parameter[0];
+
+ if (allowed) {
+ state->_vm->_menu->accessAllow();
+ } else {
+ state->_vm->_menu->accessDeny();
}
}
-void cmdShowMouse(AgiGame *state, uint8 *p) {
- g_system->showMouse(true);
+void cmdFenceMouse(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr1 = parameter[0];
+ uint16 varNr2 = parameter[1];
+ uint16 varNr3 = parameter[2];
+ uint16 varNr4 = parameter[3];
+
+ state->mouseFence.moveTo(varNr1, varNr2);
+ state->mouseFence.setWidth(varNr3 - varNr1);
+ state->mouseFence.setHeight(varNr4 - varNr1);
}
-void cmdFenceMouse(AgiGame *state, uint8 *p) {
- state->mouseFence.moveTo(p0, p1);
- state->mouseFence.setWidth(p2 - p0);
- state->mouseFence.setHeight(p3 - p1);
+// HoldKey was added in 2.425
+// There was no way to disable this mode until 3.098 though
+void cmdHoldKey(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if ((getVersion() < 0x2425) || (getVersion() == 0x2440)) {
+ // was not available before 2.425, but also not available in 2.440
+ warning("hold.key called, although not available for current AGI version");
+ return;
+ }
+
+ vm->_keyHoldMode = true;
}
-void cmdReleaseKey(AgiGame *state, uint8 *p) {
- if (getVersion() >= 0x3098) {
- state->_vm->_egoHoldKey = false;
+void cmdReleaseKey(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if (getVersion() < 0x3098) {
+ // was not available before 3.098
+ warning("release.key called, although not available for current AGI version");
+ return;
}
+
+ vm->_keyHoldMode = false;
}
-void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p) {
+void cmdAdjEgoMoveToXY(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
int8 x, y;
switch (logicNamesCmd[182].argumentsLength()) {
@@ -703,8 +1059,8 @@ void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p) {
// (Using arguments (0, 0), (0, 7), (0, 8), (9, 9) and (-9, 9)).
case 2:
// Both arguments are signed 8-bit (i.e. in range -128 to +127).
- x = (int8) p0;
- y = (int8) p1;
+ x = (int8) parameter[0];
+ y = (int8) parameter[1];
// Turn off ego's current movement caused with the mouse if
// adj.ego.move.to.x.y is called with other arguments than previously.
@@ -717,7 +1073,7 @@ void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p) {
// by something else because this command doesn't do any flag manipulations
// in the Amiga version - checked it with disassembly).
if (x != state->adjMouseX || y != state->adjMouseY)
- state->viewTable[EGO_VIEW_TABLE].flags &= ~fAdjEgoXY;
+ state->screenObjTable[SCREENOBJECTS_EGO_ENTRY].flags &= ~fAdjEgoXY;
state->adjMouseX = x;
state->adjMouseY = y;
@@ -727,57 +1083,74 @@ void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p) {
// TODO: Check where (if anywhere) the 0 arguments version is used
case 0:
default:
- state->viewTable[0].flags |= fAdjEgoXY;
+ state->screenObjTable[SCREENOBJECTS_EGO_ENTRY].flags |= fAdjEgoXY;
break;
}
}
-void cmdParse(AgiGame *state, uint8 *p) {
- _v[vWordNotFound] = 0;
- setflag(fEnteredCli, false);
- setflag(fSaidAcceptedInput, false);
+void cmdParse(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *text = state->_vm->_text;
+ uint16 stringNr = parameter[0];
- state->_vm->dictionaryWords(state->_vm->agiSprintf(state->strings[p0]));
+ vm->setVar(VM_VAR_WORD_NOT_FOUND, 0);
+ vm->setFlag(VM_FLAG_ENTERED_CLI, false);
+ vm->setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
+
+ vm->_words->parseUsingDictionary(text->stringPrintf(state->strings[stringNr]));
}
-void cmdCall(AgiGame *state, uint8 *p) {
+void cmdCall(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 logicNr = parameter[0];
int oldCIP;
int oldLognum;
// CM: we don't save sIP because set.scan.start can be
// used in a called script (fixes xmas demo)
oldCIP = state->_curLogic->cIP;
- oldLognum = state->lognum;
+ oldLognum = state->curLogicNr;
- state->_vm->runLogic(p0);
+ state->_vm->runLogic(logicNr);
- state->lognum = oldLognum;
- state->_curLogic = &state->logics[state->lognum];
+ state->curLogicNr = oldLognum;
+ state->_curLogic = &state->logics[state->curLogicNr];
state->_curLogic->cIP = oldCIP;
}
-void cmdCallF(AgiGame *state, uint8 *p) {
- cmdCall(state, &_v[p0]);
+void cmdCallF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ byte logicNr = vm->getVar(varNr);
+
+ cmdCall(state, vm, &logicNr);
}
-void cmdDrawPicV1(AgiGame *state, uint8 *p) {
- debugC(6, kDebugLevelScripts, "=== draw pic V1 %d ===", _v[p0]);
- state->_vm->_picture->decodePicture(_v[p0], true);
+void cmdDrawPicV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 resourceNr = vm->getVar(varNr);
- state->_vm->clearPrompt();
+ debugC(6, kDebugLevelScripts, "=== draw pic V1 %d ===", resourceNr);
+ state->_vm->_picture->decodePicture(resourceNr, true);
- // Simulate slowww computer. Many effects rely on this
- state->_vm->pause(kPausePicture);
+ // TODO: check, if this was really done
+ vm->_text->promptClear();
+
+ // Loading trigger
+ vm->artificialDelayTrigger_DrawPicture(resourceNr);
}
-void cmdDrawPic(AgiGame *state, uint8 *p) {
- debugC(6, kDebugLevelScripts, "=== draw pic %d ===", _v[p0]);
- state->_vm->_sprites->eraseBoth();
- state->_vm->_picture->decodePicture(_v[p0], true);
- state->_vm->_sprites->blitBoth();
- state->_vm->_sprites->commitBoth();
- state->pictureShown = 0;
- debugC(6, kDebugLevelScripts, "--- end of draw pic %d ---", _v[p0]);
+void cmdDrawPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ SpritesMgr *spritesMgr = state->_vm->_sprites;
+ uint16 varNr = parameter[0];
+ uint16 resourceNr = vm->getVar(varNr);
+
+ debugC(6, kDebugLevelScripts, "=== draw pic %d ===", resourceNr);
+
+ spritesMgr->eraseSprites();
+ vm->_picture->decodePicture(resourceNr, true);
+
+ spritesMgr->buildAllSpriteLists();
+ spritesMgr->drawAllSpriteLists();
+ state->pictureShown = false;
+ debugC(6, kDebugLevelScripts, "--- end of draw pic %d ---", resourceNr);
// WORKAROUND for a script bug which exists in SQ1, logic scripts
// 20 and 110. Flag 103 is not reset correctly, which leads to erroneous
@@ -790,484 +1163,620 @@ void cmdDrawPic(AgiGame *state, uint8 *p) {
// With this workaround, when the player goes back to picture 20 (1 screen
// above the ground), flag 103 is reset, thereby fixing this issue. Note
// that this is a script bug and occurs in the original interpreter as well.
- // Fixes bug #1658514: AGI: SQ1 (2.2 DOS ENG) bizzare exploding roger
- if (getGameID() == GID_SQ1 && _v[p0] == 20)
- setflag(103, false);
+ // Fixes bug #3056: AGI: SQ1 (2.2 DOS ENG) bizzare exploding roger
+ if (vm->getGameID() == GID_SQ1 && resourceNr == 20)
+ vm->setFlag(103, false);
- // Simulate slowww computer. Many effects rely on this
- state->_vm->pause(kPausePicture);
+ // Loading trigger
+ vm->artificialDelayTrigger_DrawPicture(resourceNr);
}
-void cmdShowPic(AgiGame *state, uint8 *p) {
+void cmdShowPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
debugC(6, kDebugLevelScripts, "=== show pic ===");
- setflag(fOutputMode, false);
- state->_vm->closeWindow();
- state->_vm->_picture->showPic();
- state->pictureShown = 1;
+ vm->setFlag(VM_FLAG_OUTPUT_MODE, false);
+ vm->_text->closeWindow();
+ vm->_picture->showPicWithTransition();
+ state->pictureShown = true;
debugC(6, kDebugLevelScripts, "--- end of show pic ---");
}
-void cmdLoadPic(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->eraseBoth();
- state->_vm->agiLoadResource(rPICTURE, _v[p0]);
- state->_vm->_sprites->blitBoth();
- state->_vm->_sprites->commitBoth();
+void cmdLoadPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ SpritesMgr *spritesMgr = state->_vm->_sprites;
+ uint16 varNr = parameter[0];
+ uint16 resourceNr = vm->getVar(varNr);
+
+ spritesMgr->eraseSprites();
+ vm->agiLoadResource(RESOURCETYPE_PICTURE, resourceNr);
+ spritesMgr->buildAllSpriteLists();
+ spritesMgr->drawAllSpriteLists();
}
-void cmdLoadPicV1(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rPICTURE, _v[p0]);
+void cmdLoadPicV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 varNr = parameter[0];
+ uint16 resourceNr = vm->getVar(varNr);
+
+ state->_vm->agiLoadResource(RESOURCETYPE_PICTURE, resourceNr);
}
-void cmdDiscardPic(AgiGame *state, uint8 *p) {
+void cmdDiscardPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
debugC(6, kDebugLevelScripts, "--- discard pic ---");
// do nothing
}
-void cmdOverlayPic(AgiGame *state, uint8 *p) {
+void cmdOverlayPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ SpritesMgr *spritesMgr = state->_vm->_sprites;
+ uint16 varNr = parameter[0];
+ uint16 resourceNr = vm->getVar(varNr);
+
debugC(6, kDebugLevelScripts, "--- overlay pic ---");
- state->_vm->_sprites->eraseBoth();
- state->_vm->_picture->decodePicture(_v[p0], false);
- state->_vm->_sprites->blitBoth();
- state->pictureShown = 0;
- state->_vm->_sprites->commitBoth();
+ spritesMgr->eraseSprites();
+ vm->_picture->decodePicture(resourceNr, false);
+ spritesMgr->buildAllSpriteLists();
+ spritesMgr->drawAllSpriteLists();
+ spritesMgr->showAllSpriteLists();
+ state->pictureShown = false;
- // Simulate slowww computer. Many effects rely on this
- state->_vm->pause(kPausePicture);
+ // Loading trigger
+ vm->artificialDelayTrigger_DrawPicture(resourceNr);
}
-void cmdShowPriScreen(AgiGame *state, uint8 *p) {
- state->_vm->_debug.priority = 1;
- state->_vm->_sprites->eraseBoth();
- state->_vm->_picture->showPic();
- state->_vm->_sprites->blitBoth();
+void cmdShowPriScreen(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ GfxMgr *gfx = state->_vm->_gfx;
+
+ gfx->debugShowMap(1); // switch to priority map
state->_vm->waitKey();
- state->_vm->_debug.priority = 0;
- state->_vm->_sprites->eraseBoth();
- state->_vm->_picture->showPic();
- state->_vm->_sprites->blitBoth();
+ gfx->debugShowMap(0); // switch back to visual map
}
-void cmdAnimateObj(AgiGame *state, uint8 *p) {
+void cmdAnimateObj(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
if (getVersion() < 0x2000) {
- if (vt.flags & fDidntMove)
+ if (screenObj->flags & fDidntMove)
return;
} else {
- if (vt.flags & fAnimated)
+ if (screenObj->flags & fAnimated)
return;
}
- debugC(4, kDebugLevelScripts, "animate vt entry #%d", p0);
- vt.flags = fAnimated | fUpdate | fCycling;
+ debugC(4, kDebugLevelScripts, "animate vt entry #%d", objectNr);
+ screenObj->flags = fAnimated | fUpdate | fCycling;
if (getVersion() < 0x2000) {
- vt.flags |= fDidntMove;
+ screenObj->flags |= fDidntMove;
}
- vt.motion = kMotionNormal;
- vt.cycle = kCycleNormal;
- vt.direction = 0;
+ screenObj->motionType = kMotionNormal;
+ screenObj->cycle = kCycleNormal;
+ screenObj->direction = 0;
}
-void cmdUnanimateAll(AgiGame *state, uint8 *p) {
+void cmdUnanimateAll(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
int i;
- for (i = 0; i < MAX_VIEWTABLE; i++)
- state->viewTable[i].flags &= ~(fAnimated | fDrawn);
+ state->_vm->_sprites->eraseSprites();
+
+ for (i = 0; i < SCREENOBJECTS_MAX; i++)
+ state->screenObjTable[i].flags &= ~(fAnimated | fDrawn);
}
-void cmdDraw(AgiGame *state, uint8 *p) {
- if (vt.flags & fDrawn)
- return;
+void cmdDraw(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- if (vt.ySize <= 0 || vt.xSize <= 0)
+ if (screenObj->flags & fDrawn)
return;
- debugC(4, kDebugLevelScripts, "draw entry %d", vt.entry);
+// if (vt.ySize <= 0 || vt.xSize <= 0)
+// return;
+
+ debugC(4, kDebugLevelScripts, "draw entry %d", screenObj->objectNr);
- vt.flags |= fUpdate;
+ screenObj->flags |= fUpdate;
if (getVersion() >= 0x3000) {
- state->_vm->setLoop(&vt, vt.currentLoop);
- state->_vm->setCel(&vt, vt.currentCel);
+ state->_vm->setLoop(screenObj, screenObj->currentLoopNr);
+ state->_vm->setCel(screenObj, screenObj->currentCelNr);
}
- state->_vm->fixPosition(p0);
- vt.xPos2 = vt.xPos;
- vt.yPos2 = vt.yPos;
- vt.celData2 = vt.celData;
- state->_vm->_sprites->eraseUpdSprites();
- vt.flags |= fDrawn;
-
- // WORKAROUND: This fixes a bug with AGI Fanmade game Space Trek.
- // The original workaround checked if AGI version was <= 2.440, which could
- // cause regressions with some AGI games. The original workaround no longer
- // works for Space Trek in ScummVM, as all fanmade games are set to use
- // AGI version 2.917, but it applies to all other games where AGI version is
- // <= 2.440, which was not the original purpose of this workaround. It is
- // assumed that this bug is caused by AGI Studio, so this applies to all
- // fanmade games only.
- // TODO: Investigate this further and check if any other fanmade AGI
- // games are affected. If yes, then it'd be best to set this for Space
- // Trek only
- if (getFeatures() & GF_FANMADE) // See Sarien bug #546562
- vt.flags |= fAnimated;
-
- state->_vm->_sprites->blitUpdSprites();
- vt.flags &= ~fDontupdate;
-
- state->_vm->_sprites->commitBlock(vt.xPos, vt.yPos - vt.ySize + 1, vt.xPos + vt.xSize - 1, vt.yPos, true);
-
- debugC(4, kDebugLevelScripts, "vt entry #%d flags = %02x", p0, vt.flags);
-}
-
-void cmdErase(AgiGame *state, uint8 *p) {
- if (~vt.flags & fDrawn)
- return;
+ SpritesMgr *sprites = state->_vm->_sprites;
- state->_vm->_sprites->eraseUpdSprites();
+ state->_vm->fixPosition(objectNr);
+ screenObj->xPos_prev = screenObj->xPos;
+ screenObj->yPos_prev = screenObj->yPos;
+ screenObj->xSize_prev = screenObj->xSize;
+ screenObj->ySize_prev = screenObj->ySize;
+ //screenObj->celData2 = screenObj->celData;
+ sprites->eraseRegularSprites();
+ screenObj->flags |= fDrawn;
+ sprites->buildRegularSpriteList();
+ sprites->drawRegularSpriteList();
+ sprites->showSprite(screenObj);
+ screenObj->flags &= ~fDontupdate;
- if (vt.flags & fUpdate) {
- vt.flags &= ~fDrawn;
- } else {
- state->_vm->_sprites->eraseNonupdSprites();
- vt.flags &= ~fDrawn;
- state->_vm->_sprites->blitNonupdSprites();
- }
- state->_vm->_sprites->blitUpdSprites();
+ debugC(4, kDebugLevelScripts, "vt entry #%d flags = %02x", objectNr, screenObj->flags);
+}
+
+void cmdErase(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ SpritesMgr *sprites = state->_vm->_sprites;
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- int x1, y1, x2, y2;
+ bool noUpdateFlag = false;
+
+ if (!(screenObj->flags & fDrawn))
+ return;
+
+ sprites->eraseRegularSprites();
+ if ((screenObj->flags & fUpdate) == 0) {
+ noUpdateFlag = true;
+ sprites->eraseStaticSprites();
+ }
- x1 = MIN((int)MIN(vt.xPos, vt.xPos2), MIN(vt.xPos + vt.celData->width, vt.xPos2 + vt.celData2->width));
- x2 = MAX((int)MAX(vt.xPos, vt.xPos2), MAX(vt.xPos + vt.celData->width, vt.xPos2 + vt.celData2->width));
- y1 = MIN((int)MIN(vt.yPos, vt.yPos2), MIN(vt.yPos - vt.celData->height, vt.yPos2 - vt.celData2->height));
- y2 = MAX((int)MAX(vt.yPos, vt.yPos2), MAX(vt.yPos - vt.celData->height, vt.yPos2 - vt.celData2->height));
+ screenObj->flags &= ~fDrawn;
- state->_vm->_sprites->commitBlock(x1, y1, x2, y2, true);
+ if (noUpdateFlag) {
+ sprites->buildStaticSpriteList();
+ sprites->drawStaticSpriteList();
+ }
+ sprites->buildRegularSpriteList();
+ sprites->drawRegularSpriteList();
+ sprites->showSprite(screenObj);
}
-void cmdPosition(AgiGame *state, uint8 *p) {
- vt.xPos = vt.xPos2 = p1;
- vt.yPos = vt.yPos2 = p2;
+void cmdPosition(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 xPos = parameter[1];
+ uint16 yPos = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- // WORKAROUND: Part of the fix for bug #1659209 "AGI: Space Trek sprite duplication"
- // with an accompanying identical workaround in position.v-command (i.e. command 0x26).
- // These two workarounds together make up the whole fix. The bug was caused by
- // wrongly written script data in Space Trek v1.0's scripts (At least logics 4 and 11).
- // Position-command was called with horizontal values over 200 (Outside the screen!).
- // Clipping the coordinates so the views stay wholly on-screen seems to fix the problems.
- // It is probable (Would have to check better with disassembly to be completely sure)
- // that AGI 2.440 clipped its coordinates in its position and position.v-commands
- // although AGI 2.917 certainly doesn't (Checked that with disassembly) and that's why
- // Space Trek may have worked better with AGI 2.440 than with some other AGI versions.
- // I haven't checked but if Space Trek solely abuses the position-command we wouldn't
- // strictly need the identical workaround in the position.v-command but it does make
- // for a nice symmetry.
- if (getFeatures() & GF_CLIPCOORDS)
- state->_vm->clipViewCoordinates(&vt);
+ screenObj->xPos = screenObj->xPos_prev = xPos;
+ screenObj->yPos = screenObj->yPos_prev = yPos;
}
-void cmdPositionV1(AgiGame *state, uint8 *p) {
- vt.xPos = p1;
- vt.yPos = p2;
+void cmdPositionV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 xPos = parameter[1];
+ uint16 yPos = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->xPos = xPos;
+ screenObj->yPos = yPos;
}
-void cmdPositionF(AgiGame *state, uint8 *p) {
- vt.xPos = vt.xPos2 = _v[p1];
- vt.yPos = vt.yPos2 = _v[p2];
+void cmdPositionF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr1 = parameter[1];
+ uint16 varNr2 = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- // WORKAROUND: Part of the fix for bug #1659209 "AGI: Space Trek sprite duplication"
- // with an accompanying identical workaround in position-command (i.e. command 0x25).
- // See that workaround's comment for more in-depth information.
- if (getFeatures() & GF_CLIPCOORDS)
- state->_vm->clipViewCoordinates(&vt);
+ screenObj->xPos = screenObj->xPos_prev = vm->getVar(varNr1);
+ screenObj->yPos = screenObj->yPos_prev = vm->getVar(varNr2);
}
-void cmdPositionFV1(AgiGame *state, uint8 *p) {
- vt.xPos = _v[p1];
- vt.yPos = _v[p2];
+void cmdPositionFV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr1 = parameter[1];
+ uint16 varNr2 = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->xPos = vm->getVar(varNr1);
+ screenObj->yPos = vm->getVar(varNr2);
}
-void cmdGetPosn(AgiGame *state, uint8 *p) {
- state->vars[p1] = (unsigned char)vt.xPos;
- state->vars[p2] = (unsigned char)vt.yPos;
+void cmdGetPosn(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr1 = parameter[1];
+ uint16 varNr2 = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ vm->setVar(varNr1, (unsigned char)screenObj->xPos);
+ vm->setVar(varNr2, (unsigned char)screenObj->yPos);
}
-void cmdReposition(AgiGame *state, uint8 *p) {
- int dx = (int8) _v[p1], dy = (int8) _v[p2];
+void cmdReposition(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr1 = parameter[1];
+ uint16 varNr2 = parameter[2];
+ int16 dx = (int8) vm->getVar(varNr1);
+ int16 dy = (int8) vm->getVar(varNr2);
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
debugC(4, kDebugLevelScripts, "dx=%d, dy=%d", dx, dy);
- vt.flags |= fUpdatePos;
+ screenObj->flags |= fUpdatePos;
- if (dx < 0 && vt.xPos < -dx)
- vt.xPos = 0;
+ if (dx < 0 && screenObj->xPos < -dx)
+ screenObj->xPos = 0;
else
- vt.xPos += dx;
+ screenObj->xPos += dx;
- if (dy < 0 && vt.yPos < -dy)
- vt.yPos = 0;
+ if (dy < 0 && screenObj->yPos < -dy)
+ screenObj->yPos = 0;
else
- vt.yPos += dy;
+ screenObj->yPos += dy;
- state->_vm->fixPosition(p0);
+ state->_vm->fixPosition(objectNr);
}
-void cmdRepositionV1(AgiGame *state, uint8 *p) {
- vt.xPos2 = vt.xPos;
- vt.yPos2 = vt.yPos;
- vt.flags |= fUpdatePos;
+void cmdRepositionV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 xPosPlus = parameter[1];
+ uint16 yPosPlus = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- vt.xPos = (vt.xPos + p1) & 0xff;
- vt.yPos = (vt.yPos + p2) & 0xff;
+ screenObj->xPos_prev = screenObj->xPos;
+ screenObj->yPos_prev = screenObj->yPos;
+ screenObj->flags |= fUpdatePos;
+
+ screenObj->xPos = (screenObj->xPos + xPosPlus) & 0xff;
+ screenObj->yPos = (screenObj->yPos + yPosPlus) & 0xff;
}
-void cmdRepositionTo(AgiGame *state, uint8 *p) {
- vt.xPos = p1;
- vt.yPos = p2;
- vt.flags |= fUpdatePos;
- state->_vm->fixPosition(p0);
+void cmdRepositionTo(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 xPos = parameter[1];
+ uint16 yPos = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->xPos = xPos;
+ screenObj->yPos = yPos;
+ screenObj->flags |= fUpdatePos;
+ state->_vm->fixPosition(objectNr);
}
-void cmdRepositionToF(AgiGame *state, uint8 *p) {
- vt.xPos = _v[p1];
- vt.yPos = _v[p2];
- vt.flags |= fUpdatePos;
- state->_vm->fixPosition(p0);
+void cmdRepositionToF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 varNr1 = parameter[1];
+ uint16 varNr2 = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->xPos = vm->getVar(varNr1);
+ screenObj->yPos = vm->getVar(varNr2);
+ screenObj->flags |= fUpdatePos;
+ state->_vm->fixPosition(objectNr);
}
-void cmdAddToPic(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->addToPic(p0, p1, p2, p3, p4, p5, p6);
+void cmdAddToPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 viewNr = parameter[0];
+ uint16 loopNr = parameter[1];
+ uint16 celNr = parameter[2];
+ uint16 xPos = parameter[3];
+ uint16 yPos = parameter[4];
+ uint16 priority = parameter[5];
+ uint16 border = parameter[6];
+
+ state->_vm->_sprites->addToPic(viewNr, loopNr, celNr, xPos, yPos, priority, border);
}
-void cmdAddToPicV1(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->addToPic(p0, p1, p2, p3, p4, p5, -1);
+void cmdAddToPicV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 viewNr = parameter[0];
+ uint16 loopNr = parameter[1];
+ uint16 celNr = parameter[2];
+ uint16 xPos = parameter[3];
+ uint16 yPos = parameter[4];
+ uint16 priority = parameter[5];
+
+ state->_vm->_sprites->addToPic(viewNr, loopNr, celNr, xPos, yPos, priority, -1);
}
-void cmdAddToPicF(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->addToPic(_v[p0], _v[p1], _v[p2], _v[p3], _v[p4], _v[p5], _v[p6]);
+void cmdAddToPicF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 viewNr = vm->getVar(parameter[0]);
+ uint16 loopNr = vm->getVar(parameter[1]);
+ uint16 celNr = vm->getVar(parameter[2]);
+ uint16 xPos = vm->getVar(parameter[3]);
+ uint16 yPos = vm->getVar(parameter[4]);
+ uint16 priority = vm->getVar(parameter[5]);
+ uint16 border = vm->getVar(parameter[6]);
+
+ state->_vm->_sprites->addToPic(viewNr, loopNr, celNr, xPos, yPos, priority, border);
}
-void cmdForceUpdate(AgiGame *state, uint8 *p) {
- state->_vm->_sprites->eraseBoth();
- state->_vm->_sprites->blitBoth();
- state->_vm->_sprites->commitBoth();
+void cmdForceUpdate(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ SpritesMgr *spritesMgr = state->_vm->_sprites;
+
+ spritesMgr->eraseSprites();
+ spritesMgr->buildAllSpriteLists();
+ spritesMgr->drawAllSpriteLists();
+ spritesMgr->showAllSpriteLists();
}
-void cmdReverseLoop(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
- vt.cycle = kCycleRevLoop;
- vt.flags |= (fDontupdate | fUpdate | fCycling);
- vt.parm1 = p1;
- setflag(p1, false);
+void cmdReverseLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 loopFlag = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ debugC(4, kDebugLevelScripts, "o%d, f%d", objectNr, loopFlag);
+ screenObj->cycle = kCycleRevLoop;
+ screenObj->flags |= (fDontupdate | fUpdate | fCycling);
+ screenObj->loop_flag = loopFlag;
+ state->_vm->setFlag(screenObj->loop_flag, false);
+
+ vm->cyclerActivated(screenObj);
}
-void cmdReverseLoopV1(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
- vt.cycle = kCycleRevLoop;
- state->_vm->setCel(&vt, 0);
- vt.flags |= (fDontupdate | fUpdate | fCycling);
- vt.parm1 = p1;
- vt.parm3 = 0;
+void cmdReverseLoopV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 loopFlag = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ debugC(4, kDebugLevelScripts, "o%d, f%d", objectNr, loopFlag);
+ screenObj->cycle = kCycleRevLoop;
+ state->_vm->setCel(screenObj, 0);
+ screenObj->flags |= (fDontupdate | fUpdate | fCycling);
+ screenObj->loop_flag = loopFlag;
+ //screenObj->parm3 = 0;
}
-void cmdEndOfLoop(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
- vt.cycle = kCycleEndOfLoop;
- vt.flags |= (fDontupdate | fUpdate | fCycling);
- vt.parm1 = p1;
- setflag(p1, false);
+void cmdEndOfLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 loopFlag = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ debugC(4, kDebugLevelScripts, "o%d, f%d", objectNr, loopFlag);
+ screenObj->cycle = kCycleEndOfLoop;
+ screenObj->flags |= (fDontupdate | fUpdate | fCycling);
+ screenObj->loop_flag = loopFlag;
+ vm->setFlag(screenObj->loop_flag, false);
+
+ vm->cyclerActivated(screenObj);
}
-void cmdEndOfLoopV1(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
- vt.cycle = kCycleEndOfLoop;
- state->_vm->setCel(&vt, 0);
- vt.flags |= (fDontupdate | fUpdate | fCycling);
- vt.parm1 = p1;
- vt.parm3 = 0;
+void cmdEndOfLoopV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 loopFlag = parameter[1];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ debugC(4, kDebugLevelScripts, "o%d, f%d", objectNr, loopFlag);
+ screenObj->cycle = kCycleEndOfLoop;
+ state->_vm->setCel(screenObj, 0);
+ screenObj->flags |= (fDontupdate | fUpdate | fCycling);
+ screenObj->loop_flag = loopFlag;
+ //screenObj->parm3 = 0;
}
-void cmdBlock(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "x1=%d, y1=%d, x2=%d, y2=%d", p0, p1, p2, p3);
+void cmdBlock(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 x1 = parameter[0];
+ uint16 y1 = parameter[1];
+ uint16 x2 = parameter[2];
+ uint16 y2 = parameter[3];
+
+ debugC(4, kDebugLevelScripts, "x1=%d, y1=%d, x2=%d, y2=%d", x1, y1, x2, y2);
state->block.active = true;
- state->block.x1 = p0;
- state->block.y1 = p1;
- state->block.x2 = p2;
- state->block.y2 = p3;
+ state->block.x1 = x1;
+ state->block.y1 = y1;
+ state->block.x2 = x2;
+ state->block.y2 = y2;
}
-void cmdUnblock(AgiGame *state, uint8 *p) {
+void cmdUnblock(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->block.active = false;
}
-void cmdNormalMotion(AgiGame *state, uint8 *p) {
- vt.motion = kMotionNormal;
+void cmdNormalMotion(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->motionType = kMotionNormal;
}
-void cmdStopMotion(AgiGame *state, uint8 *p) {
- vt.direction = 0;
- vt.motion = kMotionNormal;
- if (p0 == 0) { // ego only
- _v[vEgoDir] = 0;
+void cmdStopMotion(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->direction = 0;
+ screenObj->motionType = kMotionNormal;
+ if (objectNr == 0) { // ego only
+ state->_vm->setVar(VM_VAR_EGO_DIRECTION, 0);
state->playerControl = false;
}
}
-void cmdStopMotionV1(AgiGame *state, uint8 *p) {
- vt.flags &= ~fAnimated;
+void cmdStopMotionV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags &= ~fAnimated;
}
-void cmdStartMotion(AgiGame *state, uint8 *p) {
- vt.motion = kMotionNormal;
- if (p0 == 0) { // ego only
- _v[vEgoDir] = 0;
+void cmdStartMotion(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->motionType = kMotionNormal;
+ if (objectNr == 0) { // ego only
+ state->_vm->setVar(VM_VAR_EGO_DIRECTION, 0);
state->playerControl = true;
}
}
-void cmdStartMotionV1(AgiGame *state, uint8 *p) {
- vt.flags |= fAnimated;
+void cmdStartMotionV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->flags |= fAnimated;
}
-void cmdPlayerControl(AgiGame *state, uint8 *p) {
+void cmdPlayerControl(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ ScreenObjEntry *screenObjEgo = &state->screenObjTable[SCREENOBJECTS_EGO_ENTRY];
+
state->playerControl = true;
- state->viewTable[0].motion = kMotionNormal;
+
+ if (screenObjEgo->motionType != kMotionEgo)
+ screenObjEgo->motionType = kMotionNormal;
}
-void cmdProgramControl(AgiGame *state, uint8 *p) {
+void cmdProgramControl(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->playerControl = false;
}
-void cmdFollowEgo(AgiGame *state, uint8 *p) {
- vt.motion = kMotionFollowEgo;
- vt.parm1 = p1 > vt.stepSize ? p1 : vt.stepSize;
- vt.parm2 = p2;
- vt.parm3 = 0xff;
+void cmdFollowEgo(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 followStepSize = parameter[1];
+ uint16 followFlag = parameter[2];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ screenObj->motionType = kMotionFollowEgo;
+ if (followStepSize <= screenObj->stepSize) {
+ screenObj->follow_stepSize = screenObj->stepSize;
+ } else {
+ screenObj->follow_stepSize = followStepSize;
+ }
+ screenObj->follow_flag = followFlag;
+ screenObj->follow_count = 255;
if (getVersion() < 0x2000) {
- _v[p2] = 0;
- vt.flags |= fUpdate | fAnimated;
+ vm->setVar(screenObj->follow_flag, 0);
+ screenObj->flags |= fUpdate | fAnimated;
} else {
- setflag(p2, false);
- vt.flags |= fUpdate;
+ vm->setFlag(screenObj->follow_flag, false);
+ screenObj->flags |= fUpdate;
}
+
+ vm->motionActivated(screenObj);
}
-void cmdMoveObj(AgiGame *state, uint8 *p) {
+void cmdMoveObj(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 moveX = parameter[1];
+ uint16 moveY = parameter[2];
+ uint16 stepSize = parameter[3];
+ uint16 moveFlag = parameter[4];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
// _D (_D_WARN "o=%d, x=%d, y=%d, s=%d, f=%d", p0, p1, p2, p3, p4);
- vt.motion = kMotionMoveObj;
- vt.parm1 = p1;
- vt.parm2 = p2;
- vt.parm3 = vt.stepSize;
- vt.parm4 = p4;
+ screenObj->motionType = kMotionMoveObj;
+ screenObj->move_x = moveX;
+ screenObj->move_y = moveY;
+ screenObj->move_stepSize = screenObj->stepSize;
+ screenObj->move_flag = moveFlag;
- if (p3 != 0)
- vt.stepSize = p3;
+ if (stepSize != 0)
+ screenObj->stepSize = stepSize;
if (getVersion() < 0x2000) {
- _v[p4] = 0;
- vt.flags |= fUpdate | fAnimated;
+ vm->setVar(moveFlag, 0);
+ screenObj->flags |= fUpdate | fAnimated;
} else {
- setflag(p4, false);
- vt.flags |= fUpdate;
+ vm->setFlag(screenObj->move_flag, false);
+ screenObj->flags |= fUpdate;
}
- if (p0 == 0)
+ vm->motionActivated(screenObj);
+
+ if (objectNr == 0)
state->playerControl = false;
// AGI 2.272 (ddp, xmas) doesn't call move_obj!
if (getVersion() > 0x2272)
- state->_vm->moveObj(&vt);
+ vm->moveObj(screenObj);
}
-void cmdMoveObjF(AgiGame *state, uint8 *p) {
- vt.motion = kMotionMoveObj;
- vt.parm1 = _v[p1];
- vt.parm2 = _v[p2];
- vt.parm3 = vt.stepSize;
- vt.parm4 = p4;
+void cmdMoveObjF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ uint16 moveX = vm->getVar(parameter[1]);
+ uint16 moveY = vm->getVar(parameter[2]);
+ uint16 stepSize = vm->getVar(parameter[3]);
+ uint16 moveFlag = parameter[4];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
- if (_v[p3] != 0)
- vt.stepSize = _v[p3];
+ screenObj->motionType = kMotionMoveObj;
+ screenObj->move_x = moveX;
+ screenObj->move_y = moveY;
+ screenObj->move_stepSize = screenObj->stepSize;
+ screenObj->move_flag = moveFlag;
- setflag(p4, false);
- vt.flags |= fUpdate;
+ if (stepSize != 0)
+ screenObj->stepSize = stepSize;
- if (p0 == 0)
+ vm->setFlag(screenObj->move_flag, false);
+ screenObj->flags |= fUpdate;
+
+ vm->motionActivated(screenObj);
+
+ if (objectNr == 0)
state->playerControl = false;
// AGI 2.272 (ddp, xmas) doesn't call move_obj!
if (getVersion() > 0x2272)
- state->_vm->moveObj(&vt);
+ vm->moveObj(screenObj);
}
-void cmdWander(AgiGame *state, uint8 *p) {
- if (p0 == 0)
+void cmdWander(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr = parameter[0];
+ ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+ if (objectNr == 0)
state->playerControl = false;
- vt.motion = kMotionWander;
+ screenObj->motionType = kMotionWander;
if (getVersion() < 0x2000) {
- vt.flags |= fUpdate | fAnimated;
+ screenObj->flags |= fUpdate | fAnimated;
} else {
- vt.flags |= fUpdate;
+ screenObj->flags |= fUpdate;
}
+
+ vm->motionActivated(screenObj);
}
-void cmdSetGameID(AgiGame *state, uint8 *p) {
- if (state->_curLogic->texts && (p0 - 1) <= state->_curLogic->numTexts)
- Common::strlcpy(state->id, state->_curLogic->texts[p0 - 1], 8);
+void cmdSetGameID(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 textNr = parameter[0];
+
+ if (state->_curLogic->texts && (textNr - 1) <= state->_curLogic->numTexts)
+ Common::strlcpy(state->id, state->_curLogic->texts[textNr - 1], 8);
else
state->id[0] = 0;
debug(0, "Game ID: \"%s\"", state->id);
}
-void cmdPause(AgiGame *state, uint8 *p) {
- int tmp = state->clockEnabled;
- const char *b[] = { "Continue", NULL };
- const char *b_ru[] = { "\x8f\xe0\xae\xa4\xae\xab\xa6\xa8\xe2\xec", NULL };
+void cmdPause(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ // Show pause message box
+ vm->inGameTimerPause();
- state->clockEnabled = false;
+ state->_vm->_systemUI->pauseDialog();
- switch (getLanguage()) {
- case Common::RU_RUS:
- state->_vm->selectionBox(" \x88\xa3\xe0\xa0 \xae\xe1\xe2\xa0\xad\xae\xa2\xab\xa5\xad\xa0. \n\n\n", b_ru);
- break;
- default:
- state->_vm->selectionBox(" Game is paused. \n\n\n", b);
- break;
- }
- state->clockEnabled = tmp;
+ vm->inGameTimerResume();
}
-void cmdSetMenu(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, state->_curLogic->numTexts);
+void cmdSetMenu(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 textNr = parameter[0];
+
+ debugC(4, kDebugLevelScripts, "text %02x of %02x", textNr, state->_curLogic->numTexts);
- if (state->_curLogic->texts != NULL && p0 <= state->_curLogic->numTexts)
- state->_vm->_menu->add(state->_curLogic->texts[p0 - 1]);
+ if (state->_curLogic->texts != NULL && (textNr - 1) <= state->_curLogic->numTexts) {
+ const char *menuText = state->_curLogic->texts[textNr - 1];
+
+ state->_vm->_menu->addMenu(menuText);
+ }
}
-void cmdSetMenuItem(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, state->_curLogic->numTexts);
+void cmdSetMenuItem(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 textNr = parameter[0] - 1;
+ uint16 controllerSlot = parameter[1];
- if (state->_curLogic->texts != NULL && p0 <= state->_curLogic->numTexts)
- state->_vm->_menu->addItem(state->_curLogic->texts[p0 - 1], p1);
+ debugC(4, kDebugLevelScripts, "text %02x of %02x", textNr, state->_curLogic->numTexts);
+
+ if (state->_curLogic->texts != NULL && textNr <= state->_curLogic->numTexts) {
+ const char *menuItemText = state->_curLogic->texts[textNr];
+
+ state->_vm->_menu->addMenuItem(menuItemText, controllerSlot);
+ }
}
-void cmdVersion(AgiGame *state, uint8 *p) {
+void cmdVersion(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
char ver2Msg[] =
"\n"
" \n\n"
- " Emulating Sierra AGI v%x.%03x\n";
+ " ScummVM Sierra AGI v%x.%03x";
char ver3Msg[] =
"\n"
" \n\n"
- " Emulating AGI v%x.002.%03x\n";
- // no Sierra as it wraps textbox
+ "ScummVM Sierra AGI v%x.002.%03x";
Common::String verMsg = TITLE " v%s";
@@ -1278,98 +1787,112 @@ void cmdVersion(AgiGame *state, uint8 *p) {
verMsg += (maj == 2 ? ver2Msg : ver3Msg);
verMsg = Common::String::format(verMsg.c_str(), gScummVMVersion, maj, min);
- state->_vm->messageBox(verMsg.c_str());
+ state->_vm->_text->messageBox(verMsg.c_str());
}
-void cmdConfigureScreen(AgiGame *state, uint8 *p) {
- state->lineMinPrint = p0;
- state->lineUserInput = p1;
- state->lineStatus = p2;
+void cmdConfigureScreen(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+ uint16 lineMinPrint = parameter[0];
+ uint16 promptRow = parameter[1];
+ uint16 statusRow = parameter[2];
+
+ textMgr->configureScreen(lineMinPrint);
+ textMgr->statusRow_Set(statusRow);
+ textMgr->promptRow_Set(promptRow);
}
-void cmdTextScreen(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "switching to text mode");
- state->gfxMode = false;
+void cmdTextScreen(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ GfxMgr *gfxMgr = state->_vm->_gfx;
+ TextMgr *textMgr = state->_vm->_text;
- // Simulates the "bright background bit" of the PC video
- // controller.
- if (state->colorBg)
- state->colorBg |= 0x08;
+ debugC(4, kDebugLevelScripts, "switching to text mode");
- state->_vm->_gfx->clearScreen(state->colorBg);
+ state->gfxMode = false;
+ gfxMgr->setPalette(false); // set text-mode palette
+ textMgr->charAttrib_Set(textMgr->_textAttrib.foreground, textMgr->_textAttrib.background);
+ gfxMgr->clearDisplay(0);
+ textMgr->clearLines(0, 24, textMgr->_textAttrib.combinedBackground);
}
-void cmdGraphics(AgiGame *state, uint8 *p) {
+void cmdGraphics(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
debugC(4, kDebugLevelScripts, "switching to graphics mode");
- if (!state->gfxMode) {
- state->gfxMode = true;
- state->_vm->_gfx->clearScreen(0);
- state->_vm->_picture->showPic();
- state->_vm->writeStatus();
- state->_vm->writePrompt();
- }
+ state->_vm->redrawScreen();
}
-void cmdSetTextAttribute(AgiGame *state, uint8 *p) {
- state->colorFg = p0;
- state->colorBg = p1;
-
- if (state->gfxMode) {
- if (state->colorBg != 0) {
- state->colorFg = 0;
- state->colorBg = 15;
- }
- }
+void cmdSetTextAttribute(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 foreground = parameter[0];
+ int16 background = parameter[1];
+ state->_vm->_text->charAttrib_Set(foreground, background);
}
-void cmdStatus(AgiGame *state, uint8 *p) {
- state->_vm->inventory();
+void cmdStatus(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+ InventoryMgr *inventoryMgr = state->_vm->_inventory;
+
+ textMgr->inputEditOn();
+ textMgr->charAttrib_Push();
+ textMgr->charAttrib_Set(0, 15);
+
+ cmdTextScreen(state, vm, parameter);
+
+ inventoryMgr->show();
+
+ //invent_state = 0;
+ textMgr->charAttrib_Pop();
+ state->_vm->redrawScreen();
}
-void cmdQuit(AgiGame *state, uint8 *p) {
- const char *buttons[] = { "Quit", "Continue", NULL };
+void cmdQuit(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 withoutPrompt = parameter[0];
+// const char *buttons[] = { "Quit", "Continue", NULL };
state->_vm->_sound->stopSound();
- if (p0) {
+ if (withoutPrompt) {
state->_vm->quitGame();
} else {
- if (state->_vm->selectionBox(" Quit the game, or continue? \n\n\n", buttons) == 0) {
+ if (state->_vm->_systemUI->quitDialog()) {
state->_vm->quitGame();
}
}
}
-void cmdQuitV1(AgiGame *state, uint8 *p) {
+void cmdQuitV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
state->_vm->_sound->stopSound();
state->_vm->quitGame();
}
-void cmdRestartGame(AgiGame *state, uint8 *p) {
- const char *buttons[] = { "Restart", "Continue", NULL };
- int sel;
+void cmdRestartGame(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ bool doRestart = false;
state->_vm->_sound->stopSound();
- sel = getflag(fAutoRestart) ? 0 :
- state->_vm->selectionBox(" Restart game, or continue? \n\n\n", buttons);
- if (sel == 0) {
- state->_vm->_restartGame = true;
- setflag(fRestartGame, true);
- state->_vm->_menu->enableAll();
+ if (vm->getFlag(VM_FLAG_AUTO_RESTART)) {
+ doRestart = true;
+ } else {
+ doRestart = vm->_systemUI->restartDialog();
+ }
+
+ if (doRestart) {
+ vm->_restartGame = true;
+ vm->setFlag(VM_FLAG_RESTART_GAME, true);
+ vm->_menu->itemEnableAll();
}
}
-void cmdDistance(AgiGame *state, uint8 *p) {
+void cmdDistance(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 objectNr1 = parameter[0];
+ uint16 objectNr2 = parameter[1];
+ uint16 destVarNr = parameter[2];
int16 x1, y1, x2, y2, d;
- VtEntry *v0 = &state->viewTable[p0];
- VtEntry *v1 = &state->viewTable[p1];
-
- if (v0->flags & fDrawn && v1->flags & fDrawn) {
- x1 = v0->xPos + v0->xSize / 2;
- y1 = v0->yPos;
- x2 = v1->xPos + v1->xSize / 2;
- y2 = v1->yPos;
+ ScreenObjEntry *screenObj1 = &state->screenObjTable[objectNr1];
+ ScreenObjEntry *screenObj2 = &state->screenObjTable[objectNr2];
+
+ if (screenObj1->flags & fDrawn && screenObj2->flags & fDrawn) {
+ x1 = screenObj1->xPos + screenObj1->xSize / 2;
+ y1 = screenObj1->yPos;
+ x2 = screenObj2->xPos + screenObj2->xSize / 2;
+ y2 = screenObj2->yPos;
d = ABS(x1 - x2) + ABS(y1 - y2);
if (d > 0xfe)
d = 0xfe;
@@ -1377,7 +1900,8 @@ void cmdDistance(AgiGame *state, uint8 *p) {
d = 0xff;
}
- // WORKAROUND: Fixes King's Quest IV's script bug #1660424 (KQ4: Zombie bug).
+ // WORKAROUND: Fixes King's Quest IV's script bug #3067 (KQ4: Zombie bug).
+ // This bug also happens in the original interpreter.
// In the graveyard (Rooms 16 and 18) at night if you had the Obsidian Scarab (Item 4)
// and you were very close to a spot where a zombie was going to rise up from the
// ground you could reproduce the bug. Just standing there and letting the zombie
@@ -1386,7 +1910,7 @@ void cmdDistance(AgiGame *state, uint8 *p) {
// wouldn't chase Rosella around anymore. If it had worked correctly the zombie
// wouldn't have come up at all or it would have come up and gone back down
// immediately. The latter approach is the one implemented here.
- if (getGameID() == GID_KQ4 && (_v[vCurRoom] == 16 || _v[vCurRoom] == 18) && p2 >= 221 && p2 <= 223) {
+ if (vm->getGameID() == GID_KQ4 && (vm->getVar(VM_VAR_CURRENT_ROOM) == 16 || vm->getVar(VM_VAR_CURRENT_ROOM) == 18) && destVarNr >= 221 && destVarNr <= 223) {
// Rooms 16 and 18 are graveyards where three zombies come up at night. They use logics 16 and 18.
// Variables 221-223 are used to save the distance between each zombie and Rosella.
// Variables 155, 156 and 162 are used to save the state of each zombie in room 16.
@@ -1399,343 +1923,388 @@ void cmdDistance(AgiGame *state, uint8 *p) {
// a zombie or the zombie getting turned away by the scarab) we make it appear the
// zombie is far away from Rosella if the zombie is not already up and chasing her.
enum zombieStates {ZOMBIE_SET_TO_RISE_UP, ZOMBIE_RISING_UP, ZOMBIE_CHASING_EGO};
- uint8 zombieStateVarNumList[] = {155, 156, (uint8)((_v[vCurRoom] == 16) ? 162 : 158)};
- uint8 zombieNum = p2 - 221; // Zombie's number (In range 0-2)
+ uint8 zombieStateVarNumList[] = {155, 156, (uint8)((vm->getVar(VM_VAR_CURRENT_ROOM) == 16) ? 162 : 158)};
+ uint8 zombieNum = destVarNr - 221; // Zombie's number (In range 0-2)
uint8 zombieStateVarNum = zombieStateVarNumList[zombieNum]; // Number of the variable containing zombie's state
- uint8 zombieState = _v[zombieStateVarNum]; // Zombie's state
+ uint8 zombieState = vm->getVar(zombieStateVarNum); // Zombie's state
// If zombie is not chasing Rosella then set its distance from Rosella to the maximum
if (zombieState != ZOMBIE_CHASING_EGO)
d = 0xff;
}
- _v[p2] = (unsigned char)d;
+ vm->setVar(destVarNr, (unsigned char)d);
}
-void cmdAcceptInput(AgiGame *state, uint8 *p) {
+void cmdAcceptInput(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+
debugC(4, kDebugLevelScripts | kDebugLevelInput, "input normal");
- state->_vm->newInputMode(INPUT_NORMAL);
- state->inputEnabled = true;
- state->_vm->writePrompt();
+ textMgr->promptEnable();
+ textMgr->promptRedraw();
}
-void cmdPreventInput(AgiGame *state, uint8 *p) {
+void cmdPreventInput(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+
debugC(4, kDebugLevelScripts | kDebugLevelInput, "no input");
- state->_vm->newInputMode(INPUT_NONE);
- state->inputEnabled = false;
+ textMgr->promptDisable();
- // Always clear with black background. Fixes bug #3080041.
- state->_vm->clearPrompt(true);
+ textMgr->inputEditOn();
+ textMgr->clearLine(textMgr->promptRow_Get(), 0);
}
-void cmdGetString(AgiGame *state, uint8 *p) {
- int tex, row, col;
+void cmdCancelLine(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ state->_vm->_text->promptCancelLine();
+}
+
+void cmdEchoLine(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+
+ if (textMgr->promptIsEnabled()) {
+ textMgr->promptEchoLine();
+ }
+}
- debugC(4, kDebugLevelScripts, "%d %d %d %d %d", p0, p1, p2, p3, p4);
+void cmdGetString(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+ int16 stringDestNr = parameter[0];
+ int16 leadInTextNr = parameter[1] - 1;
+ int16 stringRow = parameter[2];
+ int16 stringColumn = parameter[3];
+ int16 stringMaxLen = parameter[4];
+ bool previousEditState = false;
+ const char *leadInTextPtr = nullptr;
- tex = p1 - 1;
- row = p2;
- col = p3;
+ if (stringMaxLen > TEXT_STRING_MAX_SIZE)
+ stringMaxLen = TEXT_STRING_MAX_SIZE;
+
+ debugC(4, kDebugLevelScripts, "%d %d %d %d %d", stringDestNr, leadInTextNr, stringRow, stringColumn, stringMaxLen);
+
+ previousEditState = textMgr->inputGetEditStatus();
+
+ textMgr->charPos_Push();
+ textMgr->inputEditOn();
// Workaround for SQLC bug.
// See Sarien bug #792125 for details
- if (row > 24)
- row = 24;
- if (col > 39)
- col = 39;
+// if (promptRow > 24)
+// promptRow = 24;
+// if (promptColumn > 39)
+// promptColumn = 39;
- state->_vm->newInputMode(INPUT_GETSTRING);
+ if (stringRow < 25) {
+ textMgr->charPos_Set(stringRow, stringColumn);
+ }
- if (state->_curLogic->texts != NULL && state->_curLogic->numTexts >= tex) {
- int len = strlen(state->_curLogic->texts[tex]);
+ if (state->_curLogic->texts && state->_curLogic->numTexts >= leadInTextNr) {
+ leadInTextPtr = state->_curLogic->texts[leadInTextNr];
- state->_vm->printText(state->_curLogic->texts[tex], 0, col, row, len, state->colorFg, state->colorBg);
- state->_vm->getString(col + len - 1, row, p4, p0);
+ leadInTextPtr = textMgr->stringPrintf(leadInTextPtr);
+ leadInTextPtr = textMgr->stringWordWrap(leadInTextPtr, 40); // ?? not absolutely sure
- // SGEO: display input char
- state->_vm->_gfx->printCharacter((col + len), row, state->cursorChar, state->colorFg, state->colorBg);
+ textMgr->displayText(leadInTextPtr);
}
- do {
- state->_vm->mainCycle();
- } while (state->inputMode == INPUT_GETSTRING && !(state->_vm->shouldQuit() || state->_vm->_restartGame));
+ state->_vm->cycleInnerLoopActive(CYCLE_INNERLOOP_GETSTRING);
+
+ textMgr->stringSet("");
+ textMgr->stringEdit(stringMaxLen);
+
+ // copy string to destination
+ // TODO: not sure if set all the time or only when ENTER is pressed
+ Common::strlcpy(&state->_vm->_game.strings[stringDestNr][0], (char *)textMgr->_inputString, MAX_STRINGLEN);
+
+ textMgr->charPos_Pop();
+
+ if (!previousEditState) {
+ textMgr->inputEditOff();
+ }
}
-void cmdGetNum(AgiGame *state, uint8 *p) {
- debugC(4, kDebugLevelScripts, "%d %d", p0, p1);
+void cmdGetNum(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+ int16 leadInTextNr = parameter[0] - 1;
+ int16 numberDestVarNr = parameter[1];
+ const char *leadInTextPtr = nullptr;
+ byte number = 0;
+
+ debugC(4, kDebugLevelScripts, "%d %d", leadInTextNr, numberDestVarNr);
- state->_vm->newInputMode(INPUT_GETSTRING);
+ textMgr->inputEditOn();
+ textMgr->charPos_Set(textMgr->promptRow_Get(), 0);
- if (state->_curLogic->texts != NULL && state->_curLogic->numTexts >= (p0 - 1)) {
- int len = strlen(state->_curLogic->texts[p0 - 1]);
+ if (state->_curLogic->texts && state->_curLogic->numTexts >= leadInTextNr) {
+ leadInTextPtr = state->_curLogic->texts[leadInTextNr];
- state->_vm->printText(state->_curLogic->texts[p0 - 1], 0, 0, 22, len, state->colorFg, state->colorBg);
- state->_vm->getString(len - 1, 22, 3, MAX_STRINGS);
+ leadInTextPtr = textMgr->stringPrintf(leadInTextPtr);
+ leadInTextPtr = textMgr->stringWordWrap(leadInTextPtr, 40); // ?? not absolutely sure
- // CM: display input char
- state->_vm->_gfx->printCharacter((p3 + len), 22, state->cursorChar, state->colorFg, state->colorBg);
+ textMgr->displayText(leadInTextPtr);
}
- do {
- state->_vm->mainCycle();
- } while (state->inputMode == INPUT_GETSTRING && !(state->_vm->shouldQuit() || state->_vm->_restartGame));
+ textMgr->inputEditOff();
+
+ state->_vm->cycleInnerLoopActive(CYCLE_INNERLOOP_GETNUMBER);
- _v[p1] = atoi(state->strings[MAX_STRINGS]);
+ textMgr->stringSet("");
+ textMgr->stringEdit(3);
- debugC(4, kDebugLevelScripts, "[%s] -> %d", state->strings[MAX_STRINGS], _v[p1]);
+ textMgr->promptRedraw();
- state->_vm->clearLines(22, 22, state->colorBg);
- state->_vm->flushLines(22, 22);
+ number = atoi((char *)textMgr->_inputString);
+ vm->setVar(numberDestVarNr, number);
+
+ debugC(4, kDebugLevelScripts, "[%s] -> %d", state->strings[MAX_STRINGS], number);
}
-void cmdSetCursorChar(AgiGame *state, uint8 *p) {
- if (state->_curLogic->texts != NULL && (p0 - 1) <= state->_curLogic->numTexts) {
- state->cursorChar = *state->_curLogic->texts[p0 - 1];
+void cmdSetCursorChar(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ TextMgr *textMgr = state->_vm->_text;
+ uint16 textNr = parameter[0] - 1;
+
+ if (state->_curLogic->texts != NULL && textNr <= state->_curLogic->numTexts) {
+ textMgr->inputSetCursorChar(*state->_curLogic->texts[textNr]);
} else {
// default
- state->cursorChar = '_';
+ textMgr->inputSetCursorChar('_');
}
}
-void cmdSetKey(AgiGame *state, uint8 *p) {
- int key = 256 * p1 + p0;
- int slot = -1;
+void cmdSetKey(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 key = parameter[0] + (parameter[1] << 8);
+ uint16 controllerSlot = parameter[2];
+ int16 keyMappingSlot = -1;
- for (int i = 0; i < MAX_CONTROLLERS; i++) {
- if (slot == -1 && !state->controllers[i].keycode)
- slot = i;
+ for (int i = 0; i < MAX_CONTROLLER_KEYMAPPINGS; i++) {
+ if (keyMappingSlot == -1 && !state->controllerKeyMapping[i].keycode)
+ keyMappingSlot = i;
- if (state->controllers[i].keycode == key && state->controllers[i].controller == p2)
+ if (state->controllerKeyMapping[i].keycode == key && state->controllerKeyMapping[i].controllerSlot == controllerSlot)
return;
}
- if (slot == -1) {
- warning("Number of set.keys exceeded %d", MAX_CONTROLLERS);
+ if (keyMappingSlot == -1) {
+ warning("Number of set.keys exceeded %d", MAX_CONTROLLER_KEYMAPPINGS);
return;
}
- debugC(4, kDebugLevelScripts, "cmdSetKey: %d %d %d", p0, p1, p2);
- state->controllers[slot].keycode = key;
- state->controllers[slot].controller = p2;
+ debugC(4, kDebugLevelScripts, "cmdSetKey: %d %d %d", parameter[0], parameter[1], controllerSlot);
+ state->controllerKeyMapping[keyMappingSlot].keycode = key;
+ state->controllerKeyMapping[keyMappingSlot].controllerSlot = controllerSlot;
- state->controllerOccured[p2] = false;
+ state->controllerOccured[controllerSlot] = false;
}
-void cmdSetString(AgiGame *state, uint8 *p) {
+void cmdSetString(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 stringNr = parameter[0];
+ uint16 textNr = parameter[1] - 1;
// CM: to avoid crash in Groza (str = 150)
- if (p0 > MAX_STRINGS)
+ if (stringNr > MAX_STRINGS)
return;
- strcpy(state->strings[p0], state->_curLogic->texts[p1 - 1]);
+ Common::strlcpy(state->strings[stringNr], state->_curLogic->texts[textNr], MAX_STRINGLEN);
}
-void cmdDisplay(AgiGame *state, uint8 *p) {
+void cmdDisplay(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
// V1 has 4 args
- int t = (getVersion() >= 0x2000 ? p2 : p3);
- int len = 40;
-
- char *s = state->_vm->wordWrapString(state->_curLogic->texts[t - 1], &len);
-
- state->_vm->printText(s, p1, 0, p0, 40, state->colorFg, state->colorBg);
-
- free(s);
-}
+ int16 textNr = (getVersion() >= 0x2000 ? parameter[2] : parameter[3]);
+ int16 textRow = parameter[0];
+ int16 textColumn = parameter[1];
-void cmdDisplayF(AgiGame *state, uint8 *p) {
- state->_vm->printText(state->_curLogic->texts[_v[p2] - 1], _v[p1], 0, _v[p0], 40, state->colorFg, state->colorBg);
+ state->_vm->_text->display(textNr, textRow, textColumn);
}
-void cmdClearTextRect(AgiGame *state, uint8 *p) {
- int c, x1, y1, x2, y2;
+void cmdDisplayF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textRow = vm->getVar(parameter[0]);
+ int16 textColumn = vm->getVar(parameter[1]);
+ int16 textNr = vm->getVar(parameter[2]);
- if ((c = p4) != 0)
- c = 15;
-
- x1 = p1 * CHAR_COLS;
- y1 = p0 * CHAR_LINES;
- x2 = (p3 + 1) * CHAR_COLS - 1;
- y2 = (p2 + 1) * CHAR_LINES - 1;
+ state->_vm->_text->display(textNr, textRow, textColumn);
+}
- // Added to prevent crash with x2 = 40 in the iigs demo
- if (x1 > GFX_WIDTH)
- x1 = GFX_WIDTH - 1;
- if (x2 > GFX_WIDTH)
- x2 = GFX_WIDTH - 1;
- if (y1 > GFX_HEIGHT)
- y1 = GFX_HEIGHT - 1;
- if (y2 > GFX_HEIGHT)
- y2 = GFX_HEIGHT - 1;
+void cmdClearTextRect(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textUpperRow = parameter[0];
+ int16 textUpperColumn = parameter[1];
+ int16 textLowerRow = parameter[2];
+ int16 textLowerColumn = parameter[3];
+ int16 color = state->_vm->_text->calculateTextBackground(parameter[4]);
- state->_vm->_gfx->drawRectangle(x1, y1, x2, y2, c);
- state->_vm->_gfx->flushBlock(x1, y1, x2, y2);
+ state->_vm->_text->clearBlock(textUpperRow, textUpperColumn, textLowerRow, textLowerColumn, color);
}
-void cmdToggleMonitor(AgiGame *state, uint8 *p) {
+void cmdToggleMonitor(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
debug(0, "toggle.monitor");
}
-void cmdEchoLine(AgiGame *state, uint8 *p) {
- strcpy((char *)state->inputBuffer, (const char *)state->echoBuffer);
- state->cursorPos = strlen((char *)state->inputBuffer);
- state->hasPrompt = 0;
-}
-
-void cmdClearLines(AgiGame *state, uint8 *p) {
- uint8 l;
+void cmdClearLines(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textRowUpper = parameter[0];
+ int16 textRowLower = parameter[1];
+ int16 color = state->_vm->_text->calculateTextBackground(parameter[2]);
// Residence 44 calls clear.lines(24,0,0), see Sarien bug #558423
- l = p1 ? p1 : p0;
-
// Agent06 incorrectly calls clear.lines(1,150,0), see ScummVM bugs
// #1935838 and #1935842
- l = (l <= 24) ? l : 24;
-
- state->_vm->clearLines(p0, l, p2);
- state->_vm->flushLines(p0, l);
+ if (textRowUpper > textRowLower) {
+ warning("cmdClearLines: RowUpper higher than RowLower");
+ textRowLower = textRowUpper;
+ }
+ state->_vm->_text->clearLines(textRowUpper, textRowLower, color);
}
-void cmdPrint(AgiGame *state, uint8 *p) {
- int n = p0 < 1 ? 1 : p0;
+void cmdPrint(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textNr = parameter[0];
- state->_vm->print(state->_curLogic->texts[n - 1], 0, 0, 0);
+ state->_vm->_text->print(textNr);
}
-void cmdPrintF(AgiGame *state, uint8 *p) {
- int n = _v[p0] < 1 ? 1 : _v[p0];
+void cmdPrintF(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textNr = vm->getVar(parameter[0]);
- state->_vm->print(state->_curLogic->texts[n - 1], 0, 0, 0);
+ state->_vm->_text->print(textNr);
}
-void cmdPrintAt(AgiGame *state, uint8 *p) {
- int n = p0 < 1 ? 1 : p0;
+void cmdPrintAt(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textNr = parameter[0];
+ int16 textRow = parameter[1];
+ int16 textColumn = parameter[2];
+ int16 textWidth = parameter[3];
- debugC(4, kDebugLevelScripts, "%d %d %d %d", p0, p1, p2, p3);
+ debugC(4, kDebugLevelScripts, "%d %d %d %d", textNr, textRow, textColumn, textWidth);
- state->_vm->print(state->_curLogic->texts[n - 1], p1, p2, p3);
+ state->_vm->_text->printAt(textNr, textRow, textColumn, textWidth);
}
-void cmdPrintAtV(AgiGame *state, uint8 *p) {
- int n = _v[p0] < 1 ? 1 : _v[p0];
+void cmdPrintAtV(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ int16 textNr = vm->getVar(parameter[0]);
+ int16 textRow = parameter[1];
+ int16 textColumn = parameter[2];
+ int16 textWidth = parameter[3];
+
+ debugC(4, kDebugLevelScripts, "%d %d %d %d", textNr, textRow, textColumn, textWidth);
- state->_vm->print(state->_curLogic->texts[n - 1], p1, p2, p3);
+ state->_vm->_text->printAt(textNr, textRow, textColumn, textWidth);
}
-void cmdPushScript(AgiGame *state, uint8 *p) {
+// push.script was not available until 2.425, and also not available in 2.440
+void cmdPushScript(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
// We run AGIMOUSE always as a side effect
//if (getFeatures() & GF_AGIMOUSE || true) {
- state->vars[27] = state->_vm->_mouse.button;
- state->vars[28] = state->_vm->_mouse.x / 2;
- state->vars[29] = state->_vm->_mouse.y;
+ vm->setVar(VM_VAR_MOUSE_BUTTONSTATE, state->_vm->_mouse.button);
+ vm->setVar(VM_VAR_MOUSE_X, vm->_mouse.pos.x / 2);
+ vm->setVar(VM_VAR_MOUSE_Y, vm->_mouse.pos.y);
/*} else {
- if (getVersion() >= 0x2915) {
- debug(0, "push.script");
- }
+ if (getVersion() >= 0x2915) {
+ debug(0, "push.script");
+ }
}*/
}
-void cmdSetPriBase(AgiGame *state, uint8 *p) {
- int i, x, pri;
+void cmdSetPriBase(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ if ((getVersion() != 0x2425) && (getVersion() < 0x2936)) {
+ // was only available in the 2.425 interpreter and from 2.936 (last AGI2 version) onwards
+ // Called during KQ3 (Apple IIgs):
+ // - picking up chicken (parameter = 50)
+ // - opening store/tavern door (parameter = 19)
+ // - when pirates say "Land Ho" (parameter = 16)
+ // - when killing the dragon (parameter = 4)
+ // Also called by SQ2 (Apple IIgs):
+ // - in Vohaul's lair (SQ2 currently gets this call through, which breaks some priority)
+ // TODO: Figure out what's going on
+ warning("set.pri.base called, although not available for current AGI version");
+ return;
+ }
- debug(0, "Priority base set to %d", p0);
+ uint16 priorityBase = parameter[0];
- // state->alt_pri = true;
- x = (_HEIGHT - p0) * _HEIGHT / 10;
+ debug(0, "Priority base set to %d", priorityBase);
- for (i = 0; i < _HEIGHT; i++) {
- pri = (i - p0) < 0 ? 4 : (i - p0) * _HEIGHT / x + 5;
- if (pri > 15)
- pri = 15;
- state->priTable[i] = pri;
- }
+ state->_vm->_gfx->setPriorityTable(priorityBase);
}
-void cmdMousePosn(AgiGame *state, uint8 *p) {
- _v[p0] = WIN_TO_PIC_X(state->_vm->_mouse.x);
- _v[p1] = WIN_TO_PIC_Y(state->_vm->_mouse.y);
+void cmdMousePosn(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 destVarNr1 = parameter[0];
+ uint16 destVarNr2 = parameter[1];
+ int16 mouseX = vm->_mouse.pos.x;
+ int16 mouseY = vm->_mouse.pos.y;
+
+ vm->_gfx->translateDisplayPosToGameScreen(mouseX, mouseY);
+
+ vm->setVar(destVarNr1, mouseX);
+ vm->setVar(destVarNr2, mouseY);
}
-void cmdShakeScreen(AgiGame *state, uint8 *p) {
- int i;
+void cmdShakeScreen(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 shakeCount = parameter[0];
// AGIPAL uses shake.screen values between 100 and 109 to set the palette
// (Checked the original AGIPAL-hack's shake.screen-routine's disassembly).
- if (p0 >= 100 && p0 < 110) {
+ if (shakeCount >= 100 && shakeCount < 110) {
if (getFeatures() & GF_AGIPAL) {
- state->_vm->_gfx->setAGIPal(p0);
+ state->_vm->_gfx->setAGIPal(shakeCount);
return;
} else {
warning("It looks like GF_AGIPAL flag is missing");
}
}
- // Disables input while shaking to prevent bug
- // #1678230: AGI: Entering text while screen is shaking
- bool originalValue = state->inputEnabled;
- state->inputEnabled = false;
-
- state->_vm->_gfx->shakeStart();
-
- state->_vm->_sprites->commitBoth(); // Fixes SQ1 demo
- for (i = 4 * p0; i; i--) {
- state->_vm->_gfx->shakeScreen(i & 1);
- state->_vm->_gfx->flushBlock(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
- state->_vm->mainCycle();
- }
- state->_vm->_gfx->shakeEnd();
-
- // Sets input back to what it was
- state->inputEnabled = originalValue;
+ state->_vm->_gfx->shakeScreen(shakeCount);
}
-void cmdSetSpeed(AgiGame *state, uint8 *p) {
+void cmdSetSpeed(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
// V1 command
(void)state;
- (void)p;
+ (void)parameter;
// speed = _v[p0];
}
-void cmdSetItemView(AgiGame *state, uint8 *p) {
+void cmdSetItemView(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
// V1 command
(void)state;
- (void)p;
+ (void)parameter;
}
-void cmdCallV1(AgiGame *state, uint8 *p) {
- state->_vm->agiLoadResource(rLOGIC, p0);
+void cmdCallV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+
+ state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, resourceNr);
// FIXME: The following instruction looks incomplete.
// Maybe something is meant to be assigned to, or read from,
// the logic_list entry?
// state->logic_list[++state->max_logics];
// For now, just do the increment, to silence a clang warning
++state->max_logics;
- _v[13] = 1;
+ vm->setVar(13, 1); // ???? maybe create another enum vor VM Vars
}
-void cmdNewRoomV1(AgiGame *state, uint8 *p) {
+void cmdNewRoomV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = parameter[0];
+
warning("cmdNewRoomV1()");
- state->_vm->agiLoadResource(rLOGIC, p0);
+ state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, resourceNr);
state->max_logics = 1;
- state->logic_list[1] = p0;
- _v[13] = 1;
+ state->logic_list[1] = resourceNr;
+ vm->setVar(13, 1);
}
-void cmdNewRoomVV1(AgiGame *state, uint8 *p) {
+void cmdNewRoomVV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ uint16 resourceNr = vm->getVar(parameter[0]);
+
warning("cmdNewRoomVV1()");
- state->_vm->agiLoadResource(rLOGIC, _v[p0]);
+ state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, resourceNr);
state->max_logics = 1;
- state->logic_list[1] = _v[p0];
- _v[13] = 1;
+ state->logic_list[1] = resourceNr;
+ vm->setVar(13, 1);
}
-void cmdUnknown(AgiGame *state, uint8 *p) {
- warning("Skipping unknown opcode %2X", *(code + ip - 1));
+void cmdUnknown(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
+ warning("Skipping unknown opcode %2X", *(state->_curLogic->data + state->_curLogic->cIP - 1));
}
/**
* Execute a logic script
* @param n Number of the logic resource to execute
*/
-int AgiEngine::runLogic(int n) {
+int AgiEngine::runLogic(int16 logicNr) {
AgiGame *state = &_game;
uint8 op = 0;
uint8 p[CMD_BSIZE] = { 0 };
@@ -1747,25 +2316,26 @@ int AgiEngine::runLogic(int n) {
state->max_logics = 0;
debugC(2, kDebugLevelScripts, "=================");
- debugC(2, kDebugLevelScripts, "runLogic(%d)", n);
+ debugC(2, kDebugLevelScripts, "runLogic(%d)", logicNr);
- sp.script = n;
+ sp.script = logicNr;
sp.curIP = 0;
_game.execStack.push_back(sp);
// If logic not loaded, load it
- if (~_game.dirLogic[n].flags & RES_LOADED) {
- debugC(4, kDebugLevelScripts, "logic %d not loaded!", n);
- agiLoadResource(rLOGIC, n);
+ if (~_game.dirLogic[logicNr].flags & RES_LOADED) {
+ debugC(4, kDebugLevelScripts, "logic %d not loaded!", logicNr);
+ agiLoadResource(RESOURCETYPE_LOGIC, logicNr);
}
- _game.lognum = n;
- _game._curLogic = &_game.logics[_game.lognum];
+ _game.curLogicNr = logicNr;
+ _game._curLogic = &_game.logics[_game.curLogicNr];
_game._curLogic->cIP = _game._curLogic->sIP;
- _timerHack = 0;
- while (ip < _game.logics[n].size && !(shouldQuit() || _restartGame)) {
+ while (state->_curLogic->cIP < _game.logics[logicNr].size && !(shouldQuit() || _restartGame)) {
+ // TODO: old code, needs to be adjusted
+#if 0
if (_debug.enabled) {
if (_debug.steps > 0) {
if (_debug.logic0 || n) {
@@ -1778,35 +2348,31 @@ int AgiEngine::runLogic(int n) {
do {
mainCycle();
} while (!_debug.steps && _debug.enabled);
- _sprites->eraseBoth();
+ _sprites->eraseAllSprites();
}
}
+#endif
- _game.execStack.back().curIP = ip;
+ // Just a counter for every instruction, that got executed
+ _instructionCounter++;
+
+ _game.execStack.back().curIP = state->_curLogic->cIP;
char st[101];
int sz = MIN(_game.execStack.size(), 100u);
memset(st, '.', sz);
st[sz] = 0;
- switch (op = *(code + ip++)) {
- case 0xff: // if (open/close)
- testIfCode(n);
+ switch (op = *(state->_curLogic->data + state->_curLogic->cIP++)) {
+ case 0xff: // if (open/close)
+ testIfCode(logicNr);
break;
- case 0xfe: // goto
+ case 0xfe: // goto
// +2 covers goto size
- ip += 2 + ((int16)READ_LE_UINT16(code + ip));
-
- // timer must keep running even in goto loops,
- // but AGI engine can't do that :(
- if (_timerHack > 20) {
- pollTimer();
- updateTimer();
- _timerHack = 0;
- }
+ state->_curLogic->cIP += 2 + ((int16)READ_LE_UINT16(state->_curLogic->data + state->_curLogic->cIP));
break;
- case 0x00: // return
- debugC(2, kDebugLevelScripts, "%sreturn() // Logic %d", st, n);
+ case 0x00: // return
+ debugC(2, kDebugLevelScripts, "%sreturn() // Logic %d", st, logicNr);
debugC(2, kDebugLevelScripts, "=================");
// if (getVersion() < 0x2000) {
@@ -1825,20 +2391,20 @@ int AgiEngine::runLogic(int n) {
return 1;
default:
num = logicNamesCmd[op].argumentsLength();
- memmove(p, code + ip, num);
+ memmove(p, state->_curLogic->data + state->_curLogic->cIP, num);
memset(p + num, 0, CMD_BSIZE - num);
debugC(2, kDebugLevelScripts, "%s%s(%d %d %d)", st, logicNamesCmd[op].name, p[0], p[1], p[2]);
- _agiCommands[op](&_game, p);
- ip += num;
+ _agiCommands[op](&_game, this, p);
+ state->_curLogic->cIP += num;
}
// if ((op == 0x0B || op == 0x3F || op == 0x40) && logic_index < state->max_logics) {
// n = state->logic_list[++logic_index];
// state->_curLogic = &state->logics[n];
// state->lognum = n;
-// ip = 2;
+// state->_curLogic_cIP = 2;
// warning("running logic %d\n", n);
// }
@@ -1848,13 +2414,13 @@ int AgiEngine::runLogic(int n) {
_game.execStack.pop_back();
- return 0; // after executing new.room()
+ return 0; // after executing new.room()
}
void AgiEngine::executeAgiCommand(uint8 op, uint8 *p) {
debugC(2, kDebugLevelScripts, "%s(%d %d %d)", logicNamesCmd[op].name, p[0], p[1], p[2]);
- _agiCommands[op](&_game, p);
+ _agiCommands[op](&_game, this, p);
}
} // End of namespace Agi